diff --git a/.gitignore b/.gitignore index bec6213641..6db0f78ba2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ -/.project -/.classpath -/.settings +.project +.classpath +.settings +*.iml +*.ipr +*.iws +.idea/ +.geany /target +*/target /reports -/src/main/java/io/netty/util/Version.java -/*.iml -/*.ipr -/*.iws -/*.geany +*/reports \ No newline at end of file diff --git a/all/assembly.xml b/all/assembly.xml new file mode 100644 index 0000000000..cb270c88cf --- /dev/null +++ b/all/assembly.xml @@ -0,0 +1,29 @@ + + + + all-in-one + + jar + + false + + + + test + true + true + false + true + + ${project.groupId}:* + + + + io/netty/** + + + + + diff --git a/all/pom.xml b/all/pom.xml new file mode 100644 index 0000000000..f58e791e74 --- /dev/null +++ b/all/pom.xml @@ -0,0 +1,117 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty + jar + + Netty/All-in-One + + + + + ${project.groupId} + netty-example + ${project.version} + test + + + + + + + maven-assembly-plugin + 2.2.2 + + + all-in-one + package + + single + + + false + + ${project.basedir}/assembly.xml + + gnu + + + + + + + + maven-resources-plugin + 2.4.3 + + + default-resources + none + + + default-testResources + none + + + + + maven-compiler-plugin + 2.3.2 + + + default-compile + none + + + default-testCompile + none + + + + + maven-surefire-plugin + 2.7.2 + + + default-test + none + + + + + maven-jar-plugin + 2.3.2 + + + default-jar + none + + + + + + + diff --git a/buffer/pom.xml b/buffer/pom.xml new file mode 100644 index 0000000000..eb1d841c09 --- /dev/null +++ b/buffer/pom.xml @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-buffer + jar + + Netty/Buffer + + + + ${project.groupId} + netty-common + ${project.version} + + + + diff --git a/src/main/java/io/netty/buffer/AbstractChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/AbstractChannelBuffer.java similarity index 99% rename from src/main/java/io/netty/buffer/AbstractChannelBuffer.java rename to buffer/src/main/java/io/netty/buffer/AbstractChannelBuffer.java index 0350163627..76789fae35 100644 --- a/src/main/java/io/netty/buffer/AbstractChannelBuffer.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractChannelBuffer.java @@ -135,7 +135,7 @@ public abstract class AbstractChannelBuffer implements ChannelBuffer { @Override public boolean getBoolean(int index) { - return (getByte(index) == 1); + return getByte(index) != 0; } @Override @@ -278,7 +278,7 @@ public abstract class AbstractChannelBuffer implements ChannelBuffer { @Override public boolean readBoolean() { - return (readByte() == 1); + return readByte() != 0; } @Override diff --git a/src/main/java/io/netty/buffer/AbstractChannelBufferFactory.java b/buffer/src/main/java/io/netty/buffer/AbstractChannelBufferFactory.java similarity index 100% rename from src/main/java/io/netty/buffer/AbstractChannelBufferFactory.java rename to buffer/src/main/java/io/netty/buffer/AbstractChannelBufferFactory.java diff --git a/src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java similarity index 62% rename from src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java rename to buffer/src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java index 4ba94b8609..854749987f 100644 --- a/src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java +++ b/buffer/src/main/java/io/netty/buffer/BigEndianHeapChannelBuffer.java @@ -59,67 +59,67 @@ public class BigEndianHeapChannelBuffer extends HeapChannelBuffer { @Override public short getShort(int index) { - return (short) (array[index] << 8 | array[index+1] & 0xFF); + return (short) (array[index] << 8 | array[index + 1] & 0xFF); } @Override public int getUnsignedMedium(int index) { - return (array[index] & 0xff) << 16 | - (array[index+1] & 0xff) << 8 | - (array[index+2] & 0xff) << 0; + return (array[index] & 0xff) << 16 | + (array[index + 1] & 0xff) << 8 | + (array[index + 2] & 0xff) << 0; } @Override public int getInt(int index) { - return (array[index] & 0xff) << 24 | - (array[index+1] & 0xff) << 16 | - (array[index+2] & 0xff) << 8 | - (array[index+3] & 0xff) << 0; + return (array[index] & 0xff) << 24 | + (array[index + 1] & 0xff) << 16 | + (array[index + 2] & 0xff) << 8 | + (array[index + 3] & 0xff) << 0; } @Override public long getLong(int index) { - return ((long) array[index] & 0xff) << 56 | - ((long) array[index+1] & 0xff) << 48 | - ((long) array[index+2] & 0xff) << 40 | - ((long) array[index+3] & 0xff) << 32 | - ((long) array[index+4] & 0xff) << 24 | - ((long) array[index+5] & 0xff) << 16 | - ((long) array[index+6] & 0xff) << 8 | - ((long) array[index+7] & 0xff) << 0; + return ((long) array[index] & 0xff) << 56 | + ((long) array[index + 1] & 0xff) << 48 | + ((long) array[index + 2] & 0xff) << 40 | + ((long) array[index + 3] & 0xff) << 32 | + ((long) array[index + 4] & 0xff) << 24 | + ((long) array[index + 5] & 0xff) << 16 | + ((long) array[index + 6] & 0xff) << 8 | + ((long) array[index + 7] & 0xff) << 0; } @Override public void setShort(int index, int value) { - array[index ] = (byte) (value >>> 8); - array[index+1] = (byte) (value >>> 0); + array[index] = (byte) (value >>> 8); + array[index + 1] = (byte) (value >>> 0); } @Override public void setMedium(int index, int value) { - array[index ] = (byte) (value >>> 16); - array[index+1] = (byte) (value >>> 8); - array[index+2] = (byte) (value >>> 0); + array[index] = (byte) (value >>> 16); + array[index + 1] = (byte) (value >>> 8); + array[index + 2] = (byte) (value >>> 0); } @Override public void setInt(int index, int value) { - array[index ] = (byte) (value >>> 24); - array[index+1] = (byte) (value >>> 16); - array[index+2] = (byte) (value >>> 8); - array[index+3] = (byte) (value >>> 0); + array[index] = (byte) (value >>> 24); + array[index + 1] = (byte) (value >>> 16); + array[index + 2] = (byte) (value >>> 8); + array[index + 3] = (byte) (value >>> 0); } @Override public void setLong(int index, long value) { - array[index ] = (byte) (value >>> 56); - array[index+1] = (byte) (value >>> 48); - array[index+2] = (byte) (value >>> 40); - array[index+3] = (byte) (value >>> 32); - array[index+4] = (byte) (value >>> 24); - array[index+5] = (byte) (value >>> 16); - array[index+6] = (byte) (value >>> 8); - array[index+7] = (byte) (value >>> 0); + array[index] = (byte) (value >>> 56); + array[index + 1] = (byte) (value >>> 48); + array[index + 2] = (byte) (value >>> 40); + array[index + 3] = (byte) (value >>> 32); + array[index + 4] = (byte) (value >>> 24); + array[index + 5] = (byte) (value >>> 16); + array[index + 6] = (byte) (value >>> 8); + array[index + 7] = (byte) (value >>> 0); } @Override diff --git a/src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java similarity index 97% rename from src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java rename to buffer/src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java index 80008af030..9e99c206e3 100644 --- a/src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufferBackedChannelBuffer.java @@ -107,9 +107,9 @@ public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer { @Override public int getUnsignedMedium(int index) { - return (getByte(index) & 0xff) << 16 | - (getByte(index+1) & 0xff) << 8 | - (getByte(index+2) & 0xff) << 0; + return (getByte(index) & 0xff) << 16 | + (getByte(index + 1) & 0xff) << 8 | + (getByte(index + 2) & 0xff) << 0; } @Override @@ -172,9 +172,9 @@ public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer { @Override public void setMedium(int index, int value) { - setByte(index, (byte) (value >>> 16)); - setByte(index+1, (byte) (value >>> 8)); - setByte(index+2, (byte) (value >>> 0)); + setByte(index, (byte) (value >>> 16)); + setByte(index + 1, (byte) (value >>> 8)); + setByte(index + 2, (byte) (value >>> 0)); } @Override diff --git a/src/main/java/io/netty/buffer/ChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/ChannelBuffer.java similarity index 99% rename from src/main/java/io/netty/buffer/ChannelBuffer.java rename to buffer/src/main/java/io/netty/buffer/ChannelBuffer.java index 3c06f9a1fa..0d43b6107d 100644 --- a/src/main/java/io/netty/buffer/ChannelBuffer.java +++ b/buffer/src/main/java/io/netty/buffer/ChannelBuffer.java @@ -47,7 +47,7 @@ import java.nio.charset.UnsupportedCharsetException; * *
  * {@link ChannelBuffer} buffer = ...;
- * for (int i = 0; i < buffer.capacity(); i ++) {
+ * for (int i = 0; i < buffer.capacity(); i ++) {
  *     byte b = buffer.getByte(i);
  *     System.out.println((char) b);
  * }
@@ -130,6 +130,8 @@ import java.nio.charset.UnsupportedCharsetException;
  *      +-------------------+------------------+------------------+
  *      |                   |                  |                  |
  *      0      <=      readerIndex   <=   writerIndex    <=    capacity
+ *
+ *
  *  AFTER discardReadBytes()
  *
  *      +------------------+--------------------------------------+
@@ -160,6 +162,8 @@ import java.nio.charset.UnsupportedCharsetException;
  *      +-------------------+------------------+------------------+
  *      |                   |                  |                  |
  *      0      <=      readerIndex   <=   writerIndex    <=    capacity
+ *
+ *
  *  AFTER clear()
  *
  *      +---------------------------------------------------------+
@@ -1352,7 +1356,7 @@ public interface ChannelBuffer extends Comparable {
      * @throws IndexOutOfBoundsException
      *         if {@code src.readableBytes} is greater than
      *            {@code this.writableBytes}
- */
+     */
     void writeBytes(ChannelBuffer src);
 
     /**
@@ -1606,7 +1610,7 @@ public interface ChannelBuffer extends Comparable {
      * This method is identical to {@code buf.copy(buf.readerIndex(), buf.readableBytes())}.
      * This method does not modify {@code readerIndex} or {@code writerIndex} of
      * this buffer.
- */
+     */
     ChannelBuffer copy();
 
     /**
diff --git a/src/main/java/io/netty/buffer/ChannelBufferFactory.java b/buffer/src/main/java/io/netty/buffer/ChannelBufferFactory.java
similarity index 100%
rename from src/main/java/io/netty/buffer/ChannelBufferFactory.java
rename to buffer/src/main/java/io/netty/buffer/ChannelBufferFactory.java
diff --git a/src/main/java/io/netty/buffer/ChannelBufferIndexFinder.java b/buffer/src/main/java/io/netty/buffer/ChannelBufferIndexFinder.java
similarity index 100%
rename from src/main/java/io/netty/buffer/ChannelBufferIndexFinder.java
rename to buffer/src/main/java/io/netty/buffer/ChannelBufferIndexFinder.java
diff --git a/src/main/java/io/netty/buffer/ChannelBufferInputStream.java b/buffer/src/main/java/io/netty/buffer/ChannelBufferInputStream.java
similarity index 100%
rename from src/main/java/io/netty/buffer/ChannelBufferInputStream.java
rename to buffer/src/main/java/io/netty/buffer/ChannelBufferInputStream.java
diff --git a/src/main/java/io/netty/buffer/ChannelBufferOutputStream.java b/buffer/src/main/java/io/netty/buffer/ChannelBufferOutputStream.java
similarity index 100%
rename from src/main/java/io/netty/buffer/ChannelBufferOutputStream.java
rename to buffer/src/main/java/io/netty/buffer/ChannelBufferOutputStream.java
diff --git a/src/main/java/io/netty/buffer/ChannelBuffers.java b/buffer/src/main/java/io/netty/buffer/ChannelBuffers.java
similarity index 99%
rename from src/main/java/io/netty/buffer/ChannelBuffers.java
rename to buffer/src/main/java/io/netty/buffer/ChannelBuffers.java
index fd4df8a3d7..5f540b0a8f 100644
--- a/src/main/java/io/netty/buffer/ChannelBuffers.java
+++ b/buffer/src/main/java/io/netty/buffer/ChannelBuffers.java
@@ -84,7 +84,7 @@ import io.netty.util.CharsetUtil;
  * @apiviz.landmark
  * @apiviz.has io.netty.buffer.ChannelBuffer oneway - - creates
  */
-public class ChannelBuffers {
+public final class ChannelBuffers {
 
     /**
      * Big endian byte order.
@@ -307,7 +307,11 @@ public class ChannelBuffers {
             return EMPTY_BUFFER;
         }
         if (buffer.hasArray()) {
-            return wrappedBuffer(buffer.order(), buffer.array(), buffer.arrayOffset() + buffer.position(),buffer.remaining());
+            return wrappedBuffer(
+                    buffer.order(),
+                    buffer.array(),
+                    buffer.arrayOffset() + buffer.position(),
+                    buffer.remaining());
         } else {
             return new ByteBufferBackedChannelBuffer(buffer);
         }
diff --git a/src/main/java/io/netty/buffer/CompositeChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/CompositeChannelBuffer.java
similarity index 99%
rename from src/main/java/io/netty/buffer/CompositeChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/CompositeChannelBuffer.java
index 3fdefca805..e960ffab18 100644
--- a/src/main/java/io/netty/buffer/CompositeChannelBuffer.java
+++ b/buffer/src/main/java/io/netty/buffer/CompositeChannelBuffer.java
@@ -347,7 +347,7 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
             setByte(index + 2, (byte) value);
         } else {
             setShort(index    , (short) value);
-            setByte (index + 2, (byte) (value >>> 16));
+            setByte(index + 2, (byte) (value >>> 16));
         }
     }
 
diff --git a/src/main/java/io/netty/buffer/DirectChannelBufferFactory.java b/buffer/src/main/java/io/netty/buffer/DirectChannelBufferFactory.java
similarity index 98%
rename from src/main/java/io/netty/buffer/DirectChannelBufferFactory.java
rename to buffer/src/main/java/io/netty/buffer/DirectChannelBufferFactory.java
index 688614f39b..b86a2f71b0 100644
--- a/src/main/java/io/netty/buffer/DirectChannelBufferFactory.java
+++ b/buffer/src/main/java/io/netty/buffer/DirectChannelBufferFactory.java
@@ -57,9 +57,9 @@ public class DirectChannelBufferFactory extends AbstractChannelBufferFactory {
     private final Object bigEndianLock = new Object();
     private final Object littleEndianLock = new Object();
     private final int preallocatedBufferCapacity;
-    private ChannelBuffer preallocatedBigEndianBuffer = null;
+    private ChannelBuffer preallocatedBigEndianBuffer;
     private int preallocatedBigEndianBufferPosition;
-    private ChannelBuffer preallocatedLittleEndianBuffer = null;
+    private ChannelBuffer preallocatedLittleEndianBuffer;
     private int preallocatedLittleEndianBufferPosition;
 
     /**
diff --git a/src/main/java/io/netty/buffer/DuplicatedChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/DuplicatedChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/DuplicatedChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/DuplicatedChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/DynamicChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/DynamicChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/DynamicChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/DynamicChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/HeapChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/HeapChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/HeapChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/HeapChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/HeapChannelBufferFactory.java b/buffer/src/main/java/io/netty/buffer/HeapChannelBufferFactory.java
similarity index 100%
rename from src/main/java/io/netty/buffer/HeapChannelBufferFactory.java
rename to buffer/src/main/java/io/netty/buffer/HeapChannelBufferFactory.java
diff --git a/src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java
similarity index 63%
rename from src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java
index 5b097337a6..399cb49afc 100644
--- a/src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java
+++ b/buffer/src/main/java/io/netty/buffer/LittleEndianHeapChannelBuffer.java
@@ -59,67 +59,67 @@ public class LittleEndianHeapChannelBuffer extends HeapChannelBuffer {
 
     @Override
     public short getShort(int index) {
-        return (short) (array[index] & 0xFF | array[index+1] << 8);
+        return (short) (array[index] & 0xFF | array[index + 1] << 8);
     }
 
     @Override
     public int getUnsignedMedium(int index) {
-        return (array[index  ] & 0xff) <<  0 |
-               (array[index+1] & 0xff) <<  8 |
-               (array[index+2] & 0xff) << 16;
+        return (array[index]     & 0xff) <<  0 |
+               (array[index + 1] & 0xff) <<  8 |
+               (array[index + 2] & 0xff) << 16;
     }
 
     @Override
     public int getInt(int index) {
-        return (array[index  ] & 0xff) <<  0 |
-               (array[index+1] & 0xff) <<  8 |
-               (array[index+2] & 0xff) << 16 |
-               (array[index+3] & 0xff) << 24;
+        return (array[index]     & 0xff) <<  0 |
+               (array[index + 1] & 0xff) <<  8 |
+               (array[index + 2] & 0xff) << 16 |
+               (array[index + 3] & 0xff) << 24;
     }
 
     @Override
     public long getLong(int index) {
-        return ((long) array[index]   & 0xff) <<  0 |
-               ((long) array[index+1] & 0xff) <<  8 |
-               ((long) array[index+2] & 0xff) << 16 |
-               ((long) array[index+3] & 0xff) << 24 |
-               ((long) array[index+4] & 0xff) << 32 |
-               ((long) array[index+5] & 0xff) << 40 |
-               ((long) array[index+6] & 0xff) << 48 |
-               ((long) array[index+7] & 0xff) << 56;
+        return ((long) array[index]     & 0xff) <<  0 |
+               ((long) array[index + 1] & 0xff) <<  8 |
+               ((long) array[index + 2] & 0xff) << 16 |
+               ((long) array[index + 3] & 0xff) << 24 |
+               ((long) array[index + 4] & 0xff) << 32 |
+               ((long) array[index + 5] & 0xff) << 40 |
+               ((long) array[index + 6] & 0xff) << 48 |
+               ((long) array[index + 7] & 0xff) << 56;
     }
 
     @Override
     public void setShort(int index, int value) {
-        array[index  ] = (byte) (value >>> 0);
-        array[index+1] = (byte) (value >>> 8);
+        array[index]     = (byte) (value >>> 0);
+        array[index + 1] = (byte) (value >>> 8);
     }
 
     @Override
     public void setMedium(int index, int   value) {
-        array[index  ] = (byte) (value >>> 0);
-        array[index+1] = (byte) (value >>> 8);
-        array[index+2] = (byte) (value >>> 16);
+        array[index]     = (byte) (value >>> 0);
+        array[index + 1] = (byte) (value >>> 8);
+        array[index + 2] = (byte) (value >>> 16);
     }
 
     @Override
     public void setInt(int index, int   value) {
-        array[index  ] = (byte) (value >>> 0);
-        array[index+1] = (byte) (value >>> 8);
-        array[index+2] = (byte) (value >>> 16);
-        array[index+3] = (byte) (value >>> 24);
+        array[index]     = (byte) (value >>> 0);
+        array[index + 1] = (byte) (value >>> 8);
+        array[index + 2] = (byte) (value >>> 16);
+        array[index + 3] = (byte) (value >>> 24);
     }
 
     @Override
     public void setLong(int index, long  value) {
-        array[index  ] = (byte) (value >>> 0);
-        array[index+1] = (byte) (value >>> 8);
-        array[index+2] = (byte) (value >>> 16);
-        array[index+3] = (byte) (value >>> 24);
-        array[index+4] = (byte) (value >>> 32);
-        array[index+5] = (byte) (value >>> 40);
-        array[index+6] = (byte) (value >>> 48);
-        array[index+7] = (byte) (value >>> 56);
+        array[index]     = (byte) (value >>> 0);
+        array[index + 1] = (byte) (value >>> 8);
+        array[index + 2] = (byte) (value >>> 16);
+        array[index + 3] = (byte) (value >>> 24);
+        array[index + 4] = (byte) (value >>> 32);
+        array[index + 5] = (byte) (value >>> 40);
+        array[index + 6] = (byte) (value >>> 48);
+        array[index + 7] = (byte) (value >>> 56);
     }
 
     @Override
diff --git a/src/main/java/io/netty/buffer/ReadOnlyChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/ReadOnlyChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/ReadOnlyChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/ReadOnlyChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/SlicedChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/SlicedChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/SlicedChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/SlicedChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/TruncatedChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/TruncatedChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/TruncatedChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/TruncatedChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/WrappedChannelBuffer.java b/buffer/src/main/java/io/netty/buffer/WrappedChannelBuffer.java
similarity index 100%
rename from src/main/java/io/netty/buffer/WrappedChannelBuffer.java
rename to buffer/src/main/java/io/netty/buffer/WrappedChannelBuffer.java
diff --git a/src/main/java/io/netty/buffer/package-info.java b/buffer/src/main/java/io/netty/buffer/package-info.java
similarity index 100%
rename from src/main/java/io/netty/buffer/package-info.java
rename to buffer/src/main/java/io/netty/buffer/package-info.java
diff --git a/src/test/java/io/netty/buffer/AbstractChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/AbstractChannelBufferTest.java
similarity index 97%
rename from src/test/java/io/netty/buffer/AbstractChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/AbstractChannelBufferTest.java
index 62904c15ae..8e3df60f54 100644
--- a/src/test/java/io/netty/buffer/AbstractChannelBufferTest.java
+++ b/buffer/src/test/java/io/netty/buffer/AbstractChannelBufferTest.java
@@ -69,7 +69,7 @@ public abstract class AbstractChannelBufferTest {
         assertEquals(0, buffer.readerIndex());
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void readerIndexBoundaryCheck1() {
         try {
             buffer.writerIndex(0);
@@ -79,7 +79,7 @@ public abstract class AbstractChannelBufferTest {
         buffer.readerIndex(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void readerIndexBoundaryCheck2() {
         try {
             buffer.writerIndex(buffer.capacity());
@@ -89,7 +89,7 @@ public abstract class AbstractChannelBufferTest {
         buffer.readerIndex(buffer.capacity() + 1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void readerIndexBoundaryCheck3() {
         try {
             buffer.writerIndex(CAPACITY / 2);
@@ -107,12 +107,12 @@ public abstract class AbstractChannelBufferTest {
         buffer.readerIndex(buffer.capacity());
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void writerIndexBoundaryCheck1() {
         buffer.writerIndex(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void writerIndexBoundaryCheck2() {
         try {
             buffer.writerIndex(CAPACITY);
@@ -123,7 +123,7 @@ public abstract class AbstractChannelBufferTest {
         buffer.writerIndex(buffer.capacity() + 1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void writerIndexBoundaryCheck3() {
         try {
             buffer.writerIndex(CAPACITY);
@@ -141,72 +141,72 @@ public abstract class AbstractChannelBufferTest {
         buffer.writerIndex(CAPACITY);
     }
     
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getBooleanBoundaryCheck1() {
         buffer.getBoolean(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getBooleanBoundaryCheck2() {
         buffer.getBoolean(buffer.capacity());
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getByteBoundaryCheck1() {
         buffer.getByte(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getByteBoundaryCheck2() {
         buffer.getByte(buffer.capacity());
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getShortBoundaryCheck1() {
         buffer.getShort(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getShortBoundaryCheck2() {
         buffer.getShort(buffer.capacity() - 1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getMediumBoundaryCheck1() {
         buffer.getMedium(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getMediumBoundaryCheck2() {
         buffer.getMedium(buffer.capacity() - 2);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getIntBoundaryCheck1() {
         buffer.getInt(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getIntBoundaryCheck2() {
         buffer.getInt(buffer.capacity() - 3);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getLongBoundaryCheck1() {
         buffer.getLong(-1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getLongBoundaryCheck2() {
         buffer.getLong(buffer.capacity() - 7);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getByteArrayBoundaryCheck1() {
         buffer.getBytes(-1, new byte[0]);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getByteArrayBoundaryCheck2() {
         buffer.getBytes(-1, new byte[0], 0, 0);
     }
@@ -247,42 +247,42 @@ public abstract class AbstractChannelBufferTest {
         assertEquals(0, dst[3]);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getByteBufferBoundaryCheck() {
         buffer.getBytes(-1, ByteBuffer.allocate(0));
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void copyBoundaryCheck1() {
         buffer.copy(-1, 0);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void copyBoundaryCheck2() {
         buffer.copy(0, buffer.capacity() + 1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void copyBoundaryCheck3() {
         buffer.copy(buffer.capacity() + 1, 0);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void copyBoundaryCheck4() {
         buffer.copy(buffer.capacity(), 1);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void setIndexBoundaryCheck1() {
         buffer.setIndex(-1, CAPACITY);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void setIndexBoundaryCheck2() {
         buffer.setIndex(CAPACITY / 2, CAPACITY / 4);
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void setIndexBoundaryCheck3() {
         buffer.setIndex(0, CAPACITY + 1);
     }
@@ -309,7 +309,7 @@ public abstract class AbstractChannelBufferTest {
         assertEquals(0, dst.get(3));
     }
 
-    @Test(expected=IndexOutOfBoundsException.class)
+    @Test(expected = IndexOutOfBoundsException.class)
     public void getDirectByteBufferBoundaryCheck() {
         buffer.getBytes(-1, ByteBuffer.allocateDirect(0));
     }
@@ -754,7 +754,7 @@ public abstract class AbstractChannelBufferTest {
 
     @Test
     public void testRandomByteArrayTransfer1() {
-        byte[] value= new byte[BLOCK_SIZE];
+        byte[] value = new byte[BLOCK_SIZE];
         for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
             random.nextBytes(value);
             buffer.setBytes(i, value);
@@ -774,7 +774,7 @@ public abstract class AbstractChannelBufferTest {
 
     @Test
     public void testRandomByteArrayTransfer2() {
-        byte[] value= new byte[BLOCK_SIZE * 2];
+        byte[] value = new byte[BLOCK_SIZE * 2];
         for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
             random.nextBytes(value);
             buffer.setBytes(i, value, random.nextInt(BLOCK_SIZE), BLOCK_SIZE);
@@ -891,7 +891,7 @@ public abstract class AbstractChannelBufferTest {
 
     @Test
     public void testSequentialByteArrayTransfer1() {
-        byte[] value= new byte[BLOCK_SIZE];
+        byte[] value = new byte[BLOCK_SIZE];
         buffer.writerIndex(0);
         for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
             random.nextBytes(value);
@@ -926,7 +926,7 @@ public abstract class AbstractChannelBufferTest {
         }
 
         random.setSeed(seed);
-        byte[] expectedValue= new byte[BLOCK_SIZE * 2];
+        byte[] expectedValue = new byte[BLOCK_SIZE * 2];
         for (int i = 0; i < buffer.capacity() - BLOCK_SIZE + 1; i += BLOCK_SIZE) {
             random.nextBytes(expectedValue);
             int valueOffset = random.nextInt(BLOCK_SIZE);
diff --git a/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java
similarity index 95%
rename from src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java
index ae016cce0a..597ded9905 100644
--- a/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java
+++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeChannelBufferTest.java
@@ -102,16 +102,16 @@ public abstract class AbstractCompositeChannelBufferTest extends
         b.skipBytes(6);
         b.markReaderIndex();
         assertEquals(a.readerIndex(), b.readerIndex());
-        a.readerIndex(a.readerIndex()-1);
-        b.readerIndex(b.readerIndex()-1);
+        a.readerIndex(a.readerIndex() - 1);
+        b.readerIndex(b.readerIndex() - 1);
         assertEquals(a.readerIndex(), b.readerIndex());
-        a.writerIndex(a.writerIndex()-1);
+        a.writerIndex(a.writerIndex() - 1);
         a.markWriterIndex();
-        b.writerIndex(b.writerIndex()-1);
+        b.writerIndex(b.writerIndex() - 1);
         b.markWriterIndex();
         assertEquals(a.writerIndex(), b.writerIndex());
-        a.writerIndex(a.writerIndex()+1);
-        b.writerIndex(b.writerIndex()+1);
+        a.writerIndex(a.writerIndex() + 1);
+        b.writerIndex(b.writerIndex() + 1);
         assertEquals(a.writerIndex(), b.writerIndex());
         assertTrue(ChannelBuffers.equals(a, b));
         // now discard
@@ -256,7 +256,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1  });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }, new byte[1]));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-1);
+        b.writerIndex(b.writerIndex() - 1);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 2 }));
         assertFalse(ChannelBuffers.equals(a, b));
@@ -265,7 +265,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1 }, new byte[2]));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-2);
+        b.writerIndex(b.writerIndex() - 2);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 2 }));
         b.writeBytes(wrappedBuffer(order, new byte[] { 3 }));
@@ -275,7 +275,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 1, 3));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-1);
+        b.writerIndex(b.writerIndex() - 1);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4 }, 3, 1));
         assertTrue(ChannelBuffers.equals(a, b));
@@ -284,7 +284,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2 }, new byte[1]));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-1);
+        b.writerIndex(b.writerIndex() - 1);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 4 }));
         assertFalse(ChannelBuffers.equals(a, b));
@@ -293,7 +293,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 1, 3));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-1);
+        b.writerIndex(b.writerIndex() - 1);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 0, 1, 2, 4, 5 }, 3, 1));
         assertFalse(ChannelBuffers.equals(a, b));
@@ -302,7 +302,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3 }, new byte[7]));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-7);
+        b.writerIndex(b.writerIndex() - 7);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 4, 5, 6 }));
         b.writeBytes(
@@ -313,7 +313,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 1, 10));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-5);
+        b.writerIndex(b.writerIndex() - 5);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 5));
         assertTrue(ChannelBuffers.equals(a, b));
@@ -322,7 +322,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 6 }, new byte[5]));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-5);
+        b.writerIndex(b.writerIndex() - 5);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 7, 8, 5, 9, 10 }));
         assertFalse(ChannelBuffers.equals(a, b));
@@ -331,7 +331,7 @@ public abstract class AbstractCompositeChannelBufferTest extends
         a = wrappedBuffer(order, new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
         b = wrappedBuffer(wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 1, 10));
         // to enable writeBytes
-        b.writerIndex(b.writerIndex()-5);
+        b.writerIndex(b.writerIndex() - 5);
         b.writeBytes(
                 wrappedBuffer(order, new byte[] { 0, 1, 2, 3, 4, 6, 7, 8, 5, 9, 10, 11 }, 6, 5));
         assertFalse(ChannelBuffers.equals(a, b));
diff --git a/src/test/java/io/netty/buffer/BigEndianCompositeChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/BigEndianCompositeChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/BigEndianCompositeChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/BigEndianCompositeChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/BigEndianDirectChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/BigEndianDirectChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/BigEndianDirectChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/BigEndianDirectChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/BigEndianHeapChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/BigEndianHeapChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/BigEndianHeapChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/BigEndianHeapChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/ByteBufferBackedHeapChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/ByteBufferBackedHeapChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/ByteBufferBackedHeapChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/ByteBufferBackedHeapChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/ChannelBufferIndexFinderTest.java b/buffer/src/test/java/io/netty/buffer/ChannelBufferIndexFinderTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/ChannelBufferIndexFinderTest.java
rename to buffer/src/test/java/io/netty/buffer/ChannelBufferIndexFinderTest.java
diff --git a/src/test/java/io/netty/buffer/ChannelBufferStreamTest.java b/buffer/src/test/java/io/netty/buffer/ChannelBufferStreamTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/ChannelBufferStreamTest.java
rename to buffer/src/test/java/io/netty/buffer/ChannelBufferStreamTest.java
diff --git a/src/test/java/io/netty/buffer/ChannelBuffersTest.java b/buffer/src/test/java/io/netty/buffer/ChannelBuffersTest.java
similarity index 99%
rename from src/test/java/io/netty/buffer/ChannelBuffersTest.java
rename to buffer/src/test/java/io/netty/buffer/ChannelBuffersTest.java
index 79ef19ec81..b0b4280c66 100644
--- a/src/test/java/io/netty/buffer/ChannelBuffersTest.java
+++ b/buffer/src/test/java/io/netty/buffer/ChannelBuffersTest.java
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.easymock.classextension.EasyMock;
+import org.easymock.EasyMock;
 import org.junit.Test;
 
 /**
diff --git a/src/test/java/io/netty/buffer/DuplicateChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/DuplicateChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/DuplicateChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/DuplicateChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/DynamicChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/DynamicChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/DynamicChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/DynamicChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/LittleEndianCompositeChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/LittleEndianCompositeChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/LittleEndianCompositeChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/LittleEndianCompositeChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/LittleEndianDirectChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/LittleEndianDirectChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/LittleEndianDirectChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/LittleEndianDirectChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/LittleEndianHeapChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/LittleEndianHeapChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/LittleEndianHeapChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/LittleEndianHeapChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/ReadOnlyChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/ReadOnlyChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/ReadOnlyChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/ReadOnlyChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/SlicedChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/SlicedChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/SlicedChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/SlicedChannelBufferTest.java
diff --git a/src/test/java/io/netty/buffer/TruncatedChannelBufferTest.java b/buffer/src/test/java/io/netty/buffer/TruncatedChannelBufferTest.java
similarity index 100%
rename from src/test/java/io/netty/buffer/TruncatedChannelBufferTest.java
rename to buffer/src/test/java/io/netty/buffer/TruncatedChannelBufferTest.java
diff --git a/codec-http/pom.xml b/codec-http/pom.xml
new file mode 100644
index 0000000000..3227f5e442
--- /dev/null
+++ b/codec-http/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+
+  4.0.0
+  
+    io.netty
+    netty-parent
+    4.0.0.Alpha1-SNAPSHOT
+  
+
+  io.netty
+  netty-codec-http
+  jar
+
+  Netty/Codec/HTTP
+
+  
+    
+      ${project.groupId}
+      netty-codec
+      ${project.version}
+    
+    
+      ${project.groupId}
+      netty-handler
+      ${project.version}
+    
+  
+
+
diff --git a/src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java
index e25bfaf81b..ebb4290b5d 100644
--- a/src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractDiskHttpData.java
@@ -32,14 +32,11 @@ import io.netty.buffer.ChannelBuffers;
  */
 public abstract class AbstractDiskHttpData extends AbstractHttpData {
 
-    protected File file = null;
+    protected File file;
+    private boolean isRenamed;
+    private FileChannel fileChannel;
 
-    private boolean isRenamed = false;
-
-    private FileChannel fileChannel = null;
-
-    public AbstractDiskHttpData(String name, Charset charset, long size)
-            throws NullPointerException, IllegalArgumentException {
+    public AbstractDiskHttpData(String name, Charset charset, long size) {
         super(name, charset, size);
     }
 
@@ -191,7 +188,7 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
         file = tempFile();
         FileOutputStream outputStream = new FileOutputStream(file);
         FileChannel localfileChannel = outputStream.getChannel();
-        byte[] bytes = new byte[4096*4];
+        byte[] bytes = new byte[4096 * 4];
         ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
         int read = inputStream.read(bytes);
         int written = 0;
diff --git a/src/main/java/io/netty/handler/codec/http/AbstractHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractHttpData.java
similarity index 93%
rename from src/main/java/io/netty/handler/codec/http/AbstractHttpData.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/AbstractHttpData.java
index 3d2b38c9e9..89a5752dd5 100644
--- a/src/main/java/io/netty/handler/codec/http/AbstractHttpData.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractHttpData.java
@@ -23,17 +23,12 @@ import java.nio.charset.Charset;
 public abstract class AbstractHttpData implements HttpData {
 
     protected final String name;
-
-    protected long definedSize = 0;
-
-    protected long size = 0;
-
+    protected long definedSize;
+    protected long size;
     protected Charset charset = HttpCodecUtil.DEFAULT_CHARSET;
+    protected boolean completed;
 
-    protected boolean completed = false;
-
-    public AbstractHttpData(String name, Charset charset, long size)
-    throws NullPointerException, IllegalArgumentException {
+    public AbstractHttpData(String name, Charset charset, long size) {
         if (name == null) {
             throw new NullPointerException("name");
         }
diff --git a/src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java
similarity index 96%
rename from src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java
index 7a324a257a..bdd24455f3 100644
--- a/src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/AbstractMemoryHttpData.java
@@ -32,14 +32,11 @@ import io.netty.buffer.ChannelBuffers;
  */
 public abstract class AbstractMemoryHttpData extends AbstractHttpData {
 
-    private ChannelBuffer channelBuffer = null;
+    private ChannelBuffer channelBuffer;
+    private int chunkPosition;
+    protected boolean isRenamed;
 
-    private int chunkPosition = 0;
-
-    protected boolean isRenamed = false;
-
-    public AbstractMemoryHttpData(String name, Charset charset, long size)
-            throws NullPointerException, IllegalArgumentException {
+    public AbstractMemoryHttpData(String name, Charset charset, long size) {
         super(name, charset, size);
     }
 
@@ -64,7 +61,7 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
             throw new NullPointerException("inputStream");
         }
         ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
-        byte[] bytes = new byte[4096*4];
+        byte[] bytes = new byte[4096 * 4];
         int read = inputStream.read(bytes);
         int written = 0;
         while (read > 0) {
diff --git a/src/main/java/io/netty/handler/codec/http/Attribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/Attribute.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/Attribute.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/Attribute.java
diff --git a/src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java b/codec-http/src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java
index 5235891dba..4fd2b4370f 100644
--- a/src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/CaseIgnoringComparator.java
@@ -18,8 +18,6 @@ package io.netty.handler.codec.http;
 import java.io.Serializable;
 import java.util.Comparator;
 
-/**
- */
 final class CaseIgnoringComparator implements Comparator, Serializable {
 
     private static final long serialVersionUID = 4582133183775373862L;
diff --git a/src/main/java/io/netty/handler/codec/http/Cookie.java b/codec-http/src/main/java/io/netty/handler/codec/http/Cookie.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/Cookie.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/Cookie.java
diff --git a/src/main/java/io/netty/handler/codec/http/CookieDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/CookieDecoder.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/http/CookieDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/CookieDecoder.java
index e6f772abd6..e0c3e83ad2 100644
--- a/src/main/java/io/netty/handler/codec/http/CookieDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/CookieDecoder.java
@@ -41,10 +41,10 @@ import java.util.regex.Pattern;
  */
 public class CookieDecoder {
 
-    private final static Pattern PATTERN =
+    private static final Pattern PATTERN =
         Pattern.compile("(?:\\s|[;,])*\\$*([^;=]+)(?:=(?:[\"']((?:\\\\.|[^\"])*)[\"']|([^;,]*)))?(\\s*(?:[;,]+\\s*|$))");
 
-    private final static String COMMA = ",";
+    private static final String COMMA = ",";
 
     private final boolean lenient;
 
diff --git a/src/main/java/io/netty/handler/codec/http/CookieEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/CookieEncoder.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/http/CookieEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/CookieEncoder.java
index 845e5ac9e4..a8de9a8e46 100644
--- a/src/main/java/io/netty/handler/codec/http/CookieEncoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/CookieEncoder.java
@@ -145,7 +145,7 @@ public class CookieEncoder {
                     addQuoted(sb, CookieHeaderNames.COMMENTURL, cookie.getCommentUrl());
                 }
 
-                if(!cookie.getPorts().isEmpty()) {
+                if (!cookie.getPorts().isEmpty()) {
                     sb.append(CookieHeaderNames.PORT);
                     sb.append((char) HttpCodecUtil.EQUALS);
                     sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
@@ -189,7 +189,7 @@ public class CookieEncoder {
             }
 
             if (cookie.getVersion() >= 1) {
-                if(!cookie.getPorts().isEmpty()) {
+                if (!cookie.getPorts().isEmpty()) {
                     sb.append('$');
                     sb.append(CookieHeaderNames.PORT);
                     sb.append((char) HttpCodecUtil.EQUALS);
@@ -204,8 +204,10 @@ public class CookieEncoder {
             }
         }
 
-        if(sb.length() > 0)
-        	sb.setLength(sb.length() - 1);
+        if (sb.length() > 0) {
+            sb.setLength(sb.length() - 1);
+        }
+
         return sb.toString();
     }
 
diff --git a/src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java b/codec-http/src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java
index ab5ed057a9..2c0b7bfd1d 100644
--- a/src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/CookieHeaderNames.java
@@ -15,8 +15,6 @@
  */
 package io.netty.handler.codec.http;
 
-/**
- */
 final class CookieHeaderNames {
     static final String PATH = "Path";
 
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultCookie.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultCookie.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/DefaultCookie.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultCookie.java
index d724406ed9..eaaa7a8dd3 100644
--- a/src/main/java/io/netty/handler/codec/http/DefaultCookie.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultCookie.java
@@ -283,7 +283,7 @@ public class DefaultCookie implements Cookie {
         } else if (that.getDomain() == null) {
             return false;
         }
-	    return getDomain().equalsIgnoreCase(that.getDomain());
+        return getDomain().equalsIgnoreCase(that.getDomain());
     }
 
     @Override
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunk.java
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpChunkTrailer.java
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java
similarity index 90%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java
index ef6feabe45..c8b8836a52 100644
--- a/src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpDataFactory.java
@@ -35,11 +35,11 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
      */
     public static long MINSIZE = 0x4000;
 
-    private boolean useDisk = false;
+    private boolean useDisk;
 
-    private boolean checkSize = false;
+    private boolean checkSize;
 
-    private long minSize = 0L;
+    private long minSize;
 
     /**
      * Keep all HttpDatas until cleanAllHttpDatas() is called.
@@ -91,8 +91,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
     }
     
     @Override
-    public Attribute createAttribute(HttpRequest request, String name) throws NullPointerException,
-            IllegalArgumentException {
+    public Attribute createAttribute(HttpRequest request, String name) {
         if (useDisk) {
             Attribute attribute = new DiskAttribute(name);
             List fileToDelete = getList(request);
@@ -107,12 +106,8 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
         return new MemoryAttribute(name);
     }
 
-    /* (non-Javadoc)
-     * @see io.netty.handler.codec.http2.HttpDataFactory#createAttribute(java.lang.String, java.lang.String)
-     */
     @Override
-    public Attribute createAttribute(HttpRequest request, String name, String value)
-            throws NullPointerException, IllegalArgumentException {
+    public Attribute createAttribute(HttpRequest request, String name, String value) {
         if (useDisk) {
             Attribute attribute;
             try {
@@ -137,13 +132,10 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
         }
     }
 
-    /* (non-Javadoc)
-     * @see io.netty.handler.codec.http2.HttpDataFactory#createFileUpload(java.lang.String, java.lang.String, java.lang.String)
-     */
     @Override
     public FileUpload createFileUpload(HttpRequest request, String name, String filename,
             String contentType, String contentTransferEncoding, Charset charset,
-            long size) throws NullPointerException, IllegalArgumentException {
+            long size) {
         if (useDisk) {
             FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
                     contentTransferEncoding, charset, size);
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java
index 71cc56d2c7..f09a6363f5 100644
--- a/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpMessage.java
@@ -96,8 +96,7 @@ public class DefaultHttpMessage implements HttpMessage {
 
     @Override
     public String getHeader(final String name) {
-        List values = getHeaders(name);
-        return values.size() > 0 ? values.get(0) : null;
+        return headers.getHeader(name);
     }
 
     @Override
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpRequest.java
diff --git a/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DefaultHttpResponse.java
diff --git a/src/main/java/io/netty/handler/codec/http/DiskAttribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/DiskAttribute.java
similarity index 94%
rename from src/main/java/io/netty/handler/codec/http/DiskAttribute.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DiskAttribute.java
index e85e4caa9c..77072c00eb 100644
--- a/src/main/java/io/netty/handler/codec/http/DiskAttribute.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/DiskAttribute.java
@@ -24,7 +24,7 @@ import io.netty.buffer.ChannelBuffers;
  * Disk implementation of Attributes
  */
 public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
-    public static String baseDirectory = null;
+    public static String baseDirectory;
 
     public static boolean deleteOnExitTemporaryFile = true;
 
@@ -47,8 +47,7 @@ public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
      * @throws IllegalArgumentException
      * @throws IOException
      */
-    public DiskAttribute(String name, String value)
-            throws NullPointerException, IllegalArgumentException, IOException {
+    public DiskAttribute(String name, String value) throws IOException {
         super(name, HttpCodecUtil.DEFAULT_CHARSET, 0); // Attribute have no default size
         setValue(value);
     }
@@ -133,7 +132,7 @@ public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
 
     @Override
     protected String getDiskFilename() {
-        return getName()+postfix;
+        return getName() + postfix;
     }
 
     @Override
diff --git a/src/main/java/io/netty/handler/codec/http/DiskFileUpload.java b/codec-http/src/main/java/io/netty/handler/codec/http/DiskFileUpload.java
similarity index 81%
rename from src/main/java/io/netty/handler/codec/http/DiskFileUpload.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/DiskFileUpload.java
index 938cd5b12c..1fab99ef3a 100644
--- a/src/main/java/io/netty/handler/codec/http/DiskFileUpload.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/DiskFileUpload.java
@@ -22,7 +22,7 @@ import java.nio.charset.Charset;
  * Disk FileUpload implementation that stores file into real files
  */
 public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
-    public static String baseDirectory = null;
+    public static String baseDirectory;
 
     public static boolean deleteOnExitTemporaryFile = true;
 
@@ -30,15 +30,14 @@ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
 
     public static String postfix = ".tmp";
 
-    private String filename = null;
+    private String filename;
 
-    private String contentType = null;
+    private String contentType;
 
-    private String contentTransferEncoding = null;
+    private String contentTransferEncoding;
 
     public DiskFileUpload(String name, String filename, String contentType,
-            String contentTransferEncoding, Charset charset, long size)
-            throws NullPointerException, IllegalArgumentException {
+            String contentTransferEncoding, Charset charset, long size) {
         super(name, charset, size);
         setFilename(filename);
         setContentType(contentType);
@@ -50,17 +49,11 @@ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
         return HttpDataType.FileUpload;
     }
 
-    /* (non-Javadoc)
-     * @see io.netty.handler.codec.http2.FileUpload#getFilename()
-     */
     @Override
     public String getFilename() {
         return filename;
     }
 
-    /* (non-Javadoc)
-     * @see io.netty.handler.codec.http2.FileUpload#setFilename(java.lang.String)
-     */
     @Override
     public void setFilename(String filename) {
         if (filename == null) {
@@ -127,12 +120,12 @@ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
 
     @Override
     public String toString() {
-        return HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-            HttpPostBodyUtil.FORM_DATA+"; "+HttpPostBodyUtil.NAME+"=\"" + getName() +
-                "\"; "+HttpPostBodyUtil.FILENAME+"=\"" + filename + "\"\r\n" +
-                HttpHeaders.Names.CONTENT_TYPE+": " + contentType +
-                (charset != null? "; "+HttpHeaders.Values.CHARSET+"=" + charset + "\r\n" : "\r\n") +
-                HttpHeaders.Names.CONTENT_LENGTH+": " + length() + "\r\n" +
+        return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+            HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() +
+                "\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" +
+                HttpHeaders.Names.CONTENT_TYPE + ": " + contentType +
+                (charset != null? "; " + HttpHeaders.Values.CHARSET + "=" + charset + "\r\n" : "\r\n") +
+                HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" +
                 "Completed: " + isCompleted() +
                 "\r\nIsInMemory: " + isInMemory() + "\r\nRealFile: " +
                 file.getAbsolutePath() + " DefaultDeleteAfter: " +
diff --git a/src/main/java/io/netty/handler/codec/http/FileUpload.java b/codec-http/src/main/java/io/netty/handler/codec/http/FileUpload.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/FileUpload.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/FileUpload.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpChunk.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpChunk.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpChunk.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkAggregator.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java
index e02e76d9f6..50ded221bb 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpChunkTrailer.java
@@ -36,7 +36,7 @@ public interface HttpChunkTrailer extends HttpChunk {
      * header name, the first value is returned.
      *
      * @return the header value or {@code null} if there is no such header
- */
+     */
     String getHeader(String name);
 
     /**
diff --git a/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpClientCodec.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpClientCodec.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java
index 6652672bee..0f9c3834cf 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpCodecUtil.java
@@ -20,9 +20,7 @@ import java.util.List;
 
 import io.netty.util.CharsetUtil;
 
-/**
- */
-class HttpCodecUtil {
+final class HttpCodecUtil {
     //space ' '
     static final byte SP = 32;
 
diff --git a/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java
similarity index 50%
rename from src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java
index d03dacc03c..3c3787b34e 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java
@@ -30,16 +30,20 @@ import io.netty.handler.codec.embedder.EncoderEmbedder;
 public class HttpContentCompressor extends HttpContentEncoder {
 
     private final int compressionLevel;
+    private final int windowBits;
+    private final int memLevel;
 
     /**
-     * Creates a new handler with the default compression level (6).
+     * Creates a new handler with the default compression level (6),
+     * default window size (15) and default memory level (8).
      */
     public HttpContentCompressor() {
         this(6);
     }
 
     /**
-     * Creates a new handler with the specified compression level.
+     * Creates a new handler with the specified compression level, default
+     * window size (15) and default memory level (8).
      *
      * @param compressionLevel
      *        {@code 1} yields the fastest compression and {@code 9} yields the
@@ -47,12 +51,45 @@ public class HttpContentCompressor extends HttpContentEncoder {
      *        compression level is {@code 6}.
      */
     public HttpContentCompressor(int compressionLevel) {
+        this(compressionLevel, 15, 8);
+    }
+
+    /**
+     * Creates a new handler with the specified compression level, window size,
+     * and memory level..
+     *
+     * @param compressionLevel
+     *        {@code 1} yields the fastest compression and {@code 9} yields the
+     *        best compression.  {@code 0} means no compression.  The default
+     *        compression level is {@code 6}.
+     * @param windowBits
+     *        The base two logarithm of the size of the history buffer.  The
+     *        value should be in the range {@code 9} to {@code 15} inclusive.
+     *        Larger values result in better compression at the expense of
+     *        memory usage.  The default value is {@code 15}.
+     * @param memLevel
+     *        How much memory should be allocated for the internal compression
+     *        state.  {@code 1} uses minimum memory and {@code 9} uses maximum
+     *        memory.  Larger values result in better and faster compression
+     *        at the expense of memory usage.  The default value is {@code 8}
+     */
+    public HttpContentCompressor(int compressionLevel, int windowBits, int memLevel) {
         if (compressionLevel < 0 || compressionLevel > 9) {
             throw new IllegalArgumentException(
                     "compressionLevel: " + compressionLevel +
                     " (expected: 0-9)");
         }
+        if (windowBits < 9 || windowBits > 15) {
+            throw new IllegalArgumentException(
+                    "windowBits: " + windowBits + " (expected: 9-15)");
+        }
+        if (memLevel < 1 || memLevel > 9) {
+            throw new IllegalArgumentException(
+                    "memLevel: " + memLevel + " (expected: 1-9)");
+        }
         this.compressionLevel = compressionLevel;
+        this.windowBits = windowBits;
+        this.memLevel = memLevel;
     }
 
     @Override
@@ -83,16 +120,46 @@ public class HttpContentCompressor extends HttpContentEncoder {
         return new Result(
                 targetContentEncoding,
                 new EncoderEmbedder(
-                        new ZlibEncoder(wrapper, compressionLevel)));
+                        new ZlibEncoder(wrapper, compressionLevel, windowBits, memLevel)));
     }
 
-    private ZlibWrapper determineWrapper(String acceptEncoding) {
-        // FIXME: Use the Q value.
-        if (acceptEncoding.indexOf("gzip") >= 0) {
-            return ZlibWrapper.GZIP;
+    protected ZlibWrapper determineWrapper(String acceptEncoding) {
+        float starQ = -1.0f;
+        float gzipQ = -1.0f;
+        float deflateQ = -1.0f;
+        for (String encoding : acceptEncoding.split(",")) {
+            float q = 1.0f;
+            int equalsPos = encoding.indexOf('=');
+            if (equalsPos != -1) {
+                try {
+                    q = Float.valueOf(encoding.substring(equalsPos + 1));
+                } catch (NumberFormatException e) {
+                    // Ignore encoding
+                    q = 0.0f;
+                }
+            }
+            if (encoding.indexOf("*") >= 0) {
+                starQ = q;
+            } else if (encoding.indexOf("gzip") >= 0 && q > gzipQ) {
+                gzipQ = q;
+            } else if (encoding.indexOf("deflate") >= 0 && q > deflateQ) {
+                deflateQ = q;
+            }
         }
-        if (acceptEncoding.indexOf("deflate") >= 0) {
-            return ZlibWrapper.ZLIB;
+        if (gzipQ > 0.0f || deflateQ > 0.0f) {
+            if (gzipQ >= deflateQ) {
+                return ZlibWrapper.GZIP;
+            } else {
+                return ZlibWrapper.ZLIB;
+            }
+        }
+        if (starQ > 0.0f) {
+            if (gzipQ == -1.0f) {
+                return ZlibWrapper.GZIP;
+            }
+            if (deflateQ == -1.0f) {
+                return ZlibWrapper.ZLIB;
+            }
         }
         return null;
     }
diff --git a/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpContentDecompressor.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpContentEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpData.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpData.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpData.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpDataFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpDataFactory.java
similarity index 88%
rename from src/main/java/io/netty/handler/codec/http/HttpDataFactory.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpDataFactory.java
index 678853d9fe..2999bad731 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpDataFactory.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpDataFactory.java
@@ -29,8 +29,7 @@ public interface HttpDataFactory {
     * @throws NullPointerException
     * @throws IllegalArgumentException
     */
-    Attribute createAttribute(HttpRequest request, String name)
-           throws NullPointerException, IllegalArgumentException;
+    Attribute createAttribute(HttpRequest request, String name);
 
     /**
      *
@@ -41,8 +40,7 @@ public interface HttpDataFactory {
      * @throws NullPointerException
      * @throws IllegalArgumentException
      */
-    Attribute createAttribute(HttpRequest request, String name, String value)
-            throws NullPointerException, IllegalArgumentException;
+    Attribute createAttribute(HttpRequest request, String name, String value);
 
     /**
      *
@@ -56,7 +54,7 @@ public interface HttpDataFactory {
      */
     FileUpload createFileUpload(HttpRequest request, String name, String filename,
                                 String contentType, String contentTransferEncoding, Charset charset,
-                                long size) throws NullPointerException, IllegalArgumentException;
+                                long size);
 
     /**
      * Remove the given InterfaceHttpData from clean list (will not delete the file, except if the file
diff --git a/src/main/java/io/netty/handler/codec/http/HttpHeaderDateFormat.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaderDateFormat.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpHeaderDateFormat.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaderDateFormat.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpHeaders.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/http/HttpHeaders.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java
index fc318957ef..ab844236e6 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpHeaders.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java
@@ -49,7 +49,7 @@ public class HttpHeaders {
         /**
          * {@code "Accept-Encoding"}
          */
-        public static final String ACCEPT_ENCODING= "Accept-Encoding";
+        public static final String ACCEPT_ENCODING = "Accept-Encoding";
         /**
          * {@code "Accept-Language"}
          */
@@ -57,11 +57,11 @@ public class HttpHeaders {
         /**
          * {@code "Accept-Ranges"}
          */
-        public static final String ACCEPT_RANGES= "Accept-Ranges";
+        public static final String ACCEPT_RANGES = "Accept-Ranges";
         /**
          * {@code "Accept-Patch"}
          */
-        public static final String ACCEPT_PATCH= "Accept-Patch";
+        public static final String ACCEPT_PATCH = "Accept-Patch";
         /**
          * {@code "Age"}
          */
@@ -93,7 +93,7 @@ public class HttpHeaders {
         /**
          * {@code "Content-Language"}
          */
-        public static final String CONTENT_LANGUAGE= "Content-Language";
+        public static final String CONTENT_LANGUAGE = "Content-Language";
         /**
          * {@code "Content-Length"}
          */
@@ -117,7 +117,7 @@ public class HttpHeaders {
         /**
          * {@code "Content-Type"}
          */
-        public static final String CONTENT_TYPE= "Content-Type";
+        public static final String CONTENT_TYPE = "Content-Type";
         /**
          * {@code "Cookie"}
          */
@@ -161,7 +161,7 @@ public class HttpHeaders {
         /**
          * {@code "If-Range"}
          */
-        public static final String IF_RANGE= "If-Range";
+        public static final String IF_RANGE = "If-Range";
         /**
          * {@code "If-Unmodified-Since"}
          */
@@ -229,15 +229,15 @@ public class HttpHeaders {
         /**
          * {@code "Sec-WebSocket-Version"}
          */
-    	public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
+        public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
         /**
          * {@code "Sec-WebSocket-Key"}
          */
-    	public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
+        public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
         /**
          * {@code "Sec-WebSocket-Accept"}
          */
-    	public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
+        public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
         /**
          * {@code "Server"}
          */
diff --git a/src/main/java/io/netty/handler/codec/http/HttpMessage.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpMessage.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java
index e129f7a59c..aaa1213f7c 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpMessage.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessage.java
@@ -40,7 +40,7 @@ public interface HttpMessage {
      * value is returned.
      *
      * @return the header value or {@code null} if there is no such header
- */
+     */
     String getHeader(String name);
 
     /**
diff --git a/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java
index 5059fba641..128aa46fe2 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageDecoder.java
@@ -568,11 +568,9 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder= maxLineLength) {
                     // TODO: Respond with Bad Request and discard the traffic
                     //    or close the connection.
diff --git a/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java
similarity index 90%
rename from src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java
index e92bb38869..a4de1caecb 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMessageEncoder.java
@@ -25,6 +25,8 @@ import io.netty.buffer.ChannelBuffer;
 import io.netty.buffer.ChannelBuffers;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.HttpHeaders.Names;
+import io.netty.handler.codec.http.HttpHeaders.Values;
 import io.netty.handler.codec.oneone.OneToOneEncoder;
 import io.netty.util.CharsetUtil;
 
@@ -59,7 +61,17 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
     protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
         if (msg instanceof HttpMessage) {
             HttpMessage m = (HttpMessage) msg;
-            boolean chunked = this.chunked = HttpCodecUtil.isTransferEncodingChunked(m);
+            boolean chunked;
+            if (m.isChunked()) {
+                // check if the Transfer-Encoding is set to chunked already.
+                // if not add the header to the message
+                if (!HttpCodecUtil.isTransferEncodingChunked(m)) {
+                    m.addHeader(Names.TRANSFER_ENCODING, Values.CHUNKED);
+                }
+                chunked = this.chunked = true;
+            } else {
+                chunked = this.chunked = HttpCodecUtil.isTransferEncodingChunked(m);
+            }
             ChannelBuffer header = ChannelBuffers.dynamicBuffer(
                     channel.getConfig().getBufferFactory());
             encodeInitialLine(header, m);
diff --git a/src/main/java/io/netty/handler/codec/http/HttpMethod.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpMethod.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpMethod.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpMethod.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java
index c49cbcc488..e74e1ecdc0 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostBodyUtil.java
@@ -23,7 +23,8 @@ import io.netty.util.CharsetUtil;
 /**
  * Shared Static object between HttpMessageDecoder, HttpPostRequestDecoder and HttpPostRequestEncoder
  */
-public class HttpPostBodyUtil {
+final class HttpPostBodyUtil {
+
     public static int chunkSize = 8096;
     /**
      * HTTP content disposition header name.
diff --git a/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java
index bcd4ba6f8d..df4cf79a21 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestDecoder.java
@@ -50,12 +50,12 @@ public class HttpPostRequestDecoder {
     /**
      * Does request have a body to decode
      */
-    private boolean bodyToDecode = false;
+    private boolean bodyToDecode;
 
     /**
      * Does the last chunk already received
      */
-    private boolean isLastChunk = false;
+    private boolean isLastChunk;
 
     /**
      * HttpDatas from Body
@@ -71,28 +71,28 @@ public class HttpPostRequestDecoder {
     /**
      * The current channelBuffer
      */
-    private ChannelBuffer undecodedChunk = null;
+    private ChannelBuffer undecodedChunk;
 
     /**
      * Does this request is a Multipart request
      */
-    private boolean isMultipart = false;
+    private boolean isMultipart;
 
     /**
      * Body HttpDatas current position
      */
-    private int bodyListHttpDataRank = 0;
+    private int bodyListHttpDataRank;
 
     /**
      * If multipart, this is the boundary for the flobal multipart
      */
-    private String multipartDataBoundary = null;
+    private String multipartDataBoundary;
 
     /**
      * If multipart, there could be internal multiparts (mixed) to the global multipart.
      * Only one level is allowed.
      */
-    private String multipartMixedBoundary = null;
+    private String multipartMixedBoundary;
 
     /**
      * Current status
@@ -102,17 +102,17 @@ public class HttpPostRequestDecoder {
     /**
      * Used in Multipart
      */
-    private Map currentFieldAttributes = null;
+    private Map currentFieldAttributes;
 
     /**
      * The current FileUpload that is currently in decode process
      */
-    private FileUpload currentFileUpload = null;
+    private FileUpload currentFileUpload;
 
     /**
      * The current Attribute that is currently in decode process
      */
-    private Attribute currentAttribute = null;
+    private Attribute currentAttribute;
 
     /**
     *
@@ -122,8 +122,7 @@ public class HttpPostRequestDecoder {
     * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors
     */
     public HttpPostRequestDecoder(HttpRequest request)
-            throws ErrorDataDecoderException, IncompatibleDataDecoderException,
-            NullPointerException {
+            throws ErrorDataDecoderException, IncompatibleDataDecoderException {
         this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
                 request, HttpCodecUtil.DEFAULT_CHARSET);
     }
@@ -137,8 +136,7 @@ public class HttpPostRequestDecoder {
      * @throws ErrorDataDecoderException if the default charset was wrong when decoding or other errors
      */
     public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request)
-            throws ErrorDataDecoderException, IncompatibleDataDecoderException,
-            NullPointerException {
+            throws ErrorDataDecoderException, IncompatibleDataDecoderException {
         this(factory, request, HttpCodecUtil.DEFAULT_CHARSET);
     }
 
@@ -153,7 +151,7 @@ public class HttpPostRequestDecoder {
      */
     public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request,
             Charset charset) throws ErrorDataDecoderException,
-            IncompatibleDataDecoderException, NullPointerException {
+            IncompatibleDataDecoderException {
         if (factory == null) {
             throw new NullPointerException("factory");
         }
@@ -446,19 +444,29 @@ public class HttpPostRequestDecoder {
                 case DISPOSITION:// search '='
                     if (read == '=') {
                         currentStatus = MultiPartStatus.FIELD;
-                        equalpos = currentpos-1;
+                        equalpos = currentpos - 1;
                         String key = decodeAttribute(
-                                undecodedChunk.toString(firstpos, equalpos-firstpos, charset),
+                                undecodedChunk.toString(firstpos, equalpos - firstpos, charset),
                                 charset);
                         currentAttribute = factory.createAttribute(request, key);
                         firstpos = currentpos;
+                    } else if (read == '&') { // special empty FIELD
+                        currentStatus = MultiPartStatus.DISPOSITION;
+                        ampersandpos = currentpos - 1;
+                        String key = decodeAttribute(undecodedChunk.toString(firstpos, ampersandpos - firstpos, charset), charset);
+                        currentAttribute = factory.createAttribute(request, key);
+                        currentAttribute.setValue(""); // empty
+                        addHttpData(currentAttribute);
+                        currentAttribute = null;
+                        firstpos = currentpos;
+                        contRead = true;
                     }
                     break;
                 case FIELD:// search '&' or end of line
                     if (read == '&') {
                         currentStatus = MultiPartStatus.DISPOSITION;
-                        ampersandpos = currentpos-1;
-                        setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos-firstpos));
+                        ampersandpos = currentpos - 1;
+                        setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos - firstpos));
                         firstpos = currentpos;
                         contRead = true;
                     } else if (read == HttpCodecUtil.CR) {
@@ -467,9 +475,9 @@ public class HttpPostRequestDecoder {
                             currentpos++;
                             if (read == HttpCodecUtil.LF) {
                                 currentStatus = MultiPartStatus.PREEPILOGUE;
-                                ampersandpos = currentpos-2;
+                                ampersandpos = currentpos - 2;
                                 setFinalBuffer(
-                                        undecodedChunk.slice(firstpos, ampersandpos-firstpos));
+                                        undecodedChunk.slice(firstpos, ampersandpos - firstpos));
                                 firstpos = currentpos;
                                 contRead = false;
                             } else {
@@ -482,9 +490,9 @@ public class HttpPostRequestDecoder {
                         }
                     } else if (read == HttpCodecUtil.LF) {
                         currentStatus = MultiPartStatus.PREEPILOGUE;
-                        ampersandpos = currentpos-1;
+                        ampersandpos = currentpos - 1;
                         setFinalBuffer(
-                                undecodedChunk.slice(firstpos, ampersandpos-firstpos));
+                                undecodedChunk.slice(firstpos, ampersandpos - firstpos));
                         firstpos = currentpos;
                         contRead = false;
                     }
@@ -499,7 +507,7 @@ public class HttpPostRequestDecoder {
                 ampersandpos = currentpos;
                 if (ampersandpos > firstpos) {
                     setFinalBuffer(
-                            undecodedChunk.slice(firstpos, ampersandpos-firstpos));
+                            undecodedChunk.slice(firstpos, ampersandpos - firstpos));
                 } else if (! currentAttribute.isCompleted()) {
                     setFinalBuffer(ChannelBuffers.EMPTY_BUFFER);
                 }
@@ -511,7 +519,7 @@ public class HttpPostRequestDecoder {
                 // reset index except if to continue in case of FIELD status
                 if (currentStatus == MultiPartStatus.FIELD) {
                     currentAttribute.addContent(
-                            undecodedChunk.slice(firstpos, currentpos-firstpos),
+                            undecodedChunk.slice(firstpos, currentpos - firstpos),
                             false);
                     firstpos = currentpos;
                 }
@@ -1221,7 +1229,7 @@ public class HttpPostRequestDecoder {
                 // so go back of delimiter size
                 try {
                     currentAttribute.addContent(
-                            undecodedChunk.slice(readerIndex, lastPosition-readerIndex),
+                            undecodedChunk.slice(readerIndex, lastPosition - readerIndex),
                             true);
                 } catch (IOException e) {
                     throw new ErrorDataDecoderException(e);
@@ -1230,7 +1238,7 @@ public class HttpPostRequestDecoder {
             } else {
                 try {
                     currentAttribute.addContent(
-                            undecodedChunk.slice(readerIndex, lastPosition-readerIndex),
+                            undecodedChunk.slice(readerIndex, lastPosition - readerIndex),
                             false);
                 } catch (IOException e) {
                     throw new ErrorDataDecoderException(e);
diff --git a/src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java
similarity index 91%
rename from src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java
index 6a038423aa..0a13479608 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpPostRequestEncoder.java
@@ -51,16 +51,16 @@ public class HttpPostRequestEncoder implements ChunkedInput {
     /**
      * Chunked false by default
      */
-    private boolean isChunked = false;
+    private boolean isChunked;
 
     /**
      * InterfaceHttpData for Body (without encoding)
      */
-    private List bodyListDatas = null;
+    private List bodyListDatas;
     /**
      * The final Multipart List of InterfaceHttpData including encoding
      */
-    private List multipartHttpDatas = null;
+    private List multipartHttpDatas;
 
     /**
      * Does this request is a Multipart request
@@ -70,17 +70,17 @@ public class HttpPostRequestEncoder implements ChunkedInput {
     /**
      * If multipart, this is the boundary for the flobal multipart
      */
-    private String multipartDataBoundary = null;
+    private String multipartDataBoundary;
 
     /**
      * If multipart, there could be internal multiparts (mixed) to the global multipart.
      * Only one level is allowed.
      */
-    private String multipartMixedBoundary = null;
+    private String multipartMixedBoundary;
     /**
      * To check if the header has been finalized
      */
-    private boolean headerFinalized = false;
+    private boolean headerFinalized;
 
     /**
     *
@@ -90,7 +90,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
     * @throws ErrorDataEncoderException if the request is not a POST
     */
     public HttpPostRequestEncoder(HttpRequest request, boolean multipart)
-            throws ErrorDataEncoderException, NullPointerException {
+            throws ErrorDataEncoderException {
         this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
                 request, multipart, HttpCodecUtil.DEFAULT_CHARSET);
     }
@@ -104,7 +104,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the request is not a POST
      */
     public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart)
-            throws ErrorDataEncoderException, NullPointerException {
+            throws ErrorDataEncoderException {
         this(factory, request, multipart, HttpCodecUtil.DEFAULT_CHARSET);
     }
 
@@ -118,8 +118,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the request is not a POST
      */
     public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request,
-            boolean multipart, Charset charset) throws ErrorDataEncoderException,
-            NullPointerException {
+            boolean multipart, Charset charset) throws ErrorDataEncoderException {
         if (factory == null) {
             throw new NullPointerException("factory");
         }
@@ -157,24 +156,24 @@ public class HttpPostRequestEncoder implements ChunkedInput {
     /**
      * Does the last non empty chunk already encoded so that next chunk will be empty (last chunk)
      */
-    private boolean isLastChunk = false;
+    private boolean isLastChunk;
     /**
      * Last chunk already sent
      */
-    private boolean isLastChunkSent = false;
+    private boolean isLastChunkSent;
     /**
      * The current FileUpload that is currently in encode process
      */
-    private FileUpload currentFileUpload = null;
+    private FileUpload currentFileUpload;
     /**
      * While adding a FileUpload, is the multipart currently in Mixed Mode
      */
-    private boolean duringMixedMode = false;
+    private boolean duringMixedMode;
 
     /**
      * Global Body size
      */
-    private long globalBodySize = 0;
+    private long globalBodySize;
 
     /**
      * True if this request is a Multipart request
@@ -224,7 +223,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
      */
     public void setBodyHttpDatas(List datas)
-            throws NullPointerException, ErrorDataEncoderException {
+            throws ErrorDataEncoderException {
         if (datas == null) {
             throw new NullPointerException("datas");
         }
@@ -246,7 +245,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
      */
     public void addBodyAttribute(String name, String value)
-    throws NullPointerException, ErrorDataEncoderException {
+    throws ErrorDataEncoderException {
         if (name == null) {
             throw new NullPointerException("name");
         }
@@ -268,7 +267,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
      */
     public void addBodyFileUpload(String name, File file, String contentType, boolean isText)
-    throws NullPointerException, ErrorDataEncoderException {
+    throws ErrorDataEncoderException {
         if (name == null) {
             throw new NullPointerException("name");
         }
@@ -307,7 +306,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
      */
     public void addBodyFileUploads(String name, File[] file, String[] contentType, boolean[] isText)
-    throws NullPointerException, ErrorDataEncoderException {
+    throws ErrorDataEncoderException {
         if (file.length != contentType.length && file.length != isText.length) {
             throw new NullPointerException("Different array length");
         }
@@ -323,7 +322,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
      * @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
      */
     public void addBodyHttpData(InterfaceHttpData data)
-    throws NullPointerException, ErrorDataEncoderException {
+    throws ErrorDataEncoderException {
         if (headerFinalized) {
             throw new ErrorDataEncoderException("Cannot add value once finalized");
         }
@@ -340,12 +339,12 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                     String value = encodeAttribute(attribute.getValue(), charset);
                     Attribute newattribute = factory.createAttribute(request, key, value);
                     multipartHttpDatas.add(newattribute);
-                    globalBodySize += newattribute.getName().length()+1+
-                        newattribute.length()+1;
+                    globalBodySize += newattribute.getName().length() + 1 +
+                        newattribute.length() + 1;
                 } catch (IOException e) {
                     throw new ErrorDataEncoderException(e);
                 }
-            } else if (data instanceof FileUpload){
+            } else if (data instanceof FileUpload) {
                 // since not Multipart, only name=filename => Attribute
                 FileUpload fileUpload = (FileUpload) data;
                 // name=filename& with encoded name and filename
@@ -353,8 +352,8 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                 String value = encodeAttribute(fileUpload.getFilename(), charset);
                 Attribute newattribute = factory.createAttribute(request, key, value);
                 multipartHttpDatas.add(newattribute);
-                globalBodySize += newattribute.getName().length()+1+
-                    newattribute.length()+1;
+                globalBodySize += newattribute.getName().length() + 1 +
+                    newattribute.length() + 1;
             }
             return;
         }
@@ -393,7 +392,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
         if (data instanceof Attribute) {
             if (duringMixedMode) {
                 InternalAttribute internal = new InternalAttribute();
-                internal.addValue("\r\n--"+multipartMixedBoundary+"--");
+                internal.addValue("\r\n--" + multipartMixedBoundary + "--");
                 multipartHttpDatas.add(internal);
                 multipartMixedBoundary = null;
                 currentFileUpload = null;
@@ -404,24 +403,24 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                 // previously a data field so CRLF
                 internal.addValue("\r\n");
             }
-            internal.addValue("--"+multipartDataBoundary+"\r\n");
+            internal.addValue("--" + multipartDataBoundary + "\r\n");
             // content-disposition: form-data; name="field1"
             Attribute attribute = (Attribute) data;
-            internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-                    HttpPostBodyUtil.FORM_DATA+"; "+
-                    HttpPostBodyUtil.NAME+"=\""+
-                    encodeAttribute(attribute.getName(), charset)+"\"\r\n");
+            internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+                    HttpPostBodyUtil.FORM_DATA + "; " +
+                    HttpPostBodyUtil.NAME + "=\"" +
+                    encodeAttribute(attribute.getName(), charset) + "\"\r\n");
             Charset localcharset = attribute.getCharset();
             if (localcharset != null) {
                 // Content-Type: charset=charset
-                internal.addValue(HttpHeaders.Names.CONTENT_TYPE+": "+
-                        HttpHeaders.Values.CHARSET+"="+localcharset+"\r\n");
+                internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " +
+                        HttpHeaders.Values.CHARSET + "=" + localcharset + "\r\n");
             }
             // CRLF between body header and data
             internal.addValue("\r\n");
             multipartHttpDatas.add(internal);
             multipartHttpDatas.add(data);
-            globalBodySize += attribute.length()+internal.size();
+            globalBodySize += attribute.length() + internal.size();
         } else if (data instanceof FileUpload) {
             FileUpload fileUpload = (FileUpload) data;
             InternalAttribute internal = new InternalAttribute();
@@ -441,7 +440,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
 
                     // add endmixedmultipart delimiter, multipart body header and
                     // Data to multipart list
-                    internal.addValue("--"+multipartMixedBoundary+"--");
+                    internal.addValue("--" + multipartMixedBoundary + "--");
                     multipartHttpDatas.add(internal);
                     multipartMixedBoundary = null;
                     // start a new one (could be replaced if mixed start again from here
@@ -475,19 +474,19 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                     // Content-Type: text/plain
                     initMixedMultipart();
                     InternalAttribute pastAttribute =
-                        (InternalAttribute) multipartHttpDatas.get(multipartHttpDatas.size()-2);
+                        (InternalAttribute) multipartHttpDatas.get(multipartHttpDatas.size() - 2);
                     // remove past size
                     globalBodySize -= pastAttribute.size();
-                    String replacement = HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-                        HttpPostBodyUtil.FORM_DATA+"; "+HttpPostBodyUtil.NAME+"=\""+
-                        encodeAttribute(fileUpload.getName(), charset)+"\"\r\n";
-                    replacement += HttpHeaders.Names.CONTENT_TYPE+": "+
-                        HttpPostBodyUtil.MULTIPART_MIXED+"; "+HttpHeaders.Values.BOUNDARY+
-                        "="+multipartMixedBoundary+"\r\n\r\n";
-                    replacement += "--"+multipartMixedBoundary+"\r\n";
-                    replacement += HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-                        HttpPostBodyUtil.FILE+"; "+HttpPostBodyUtil.FILENAME+"=\""+
-                        encodeAttribute(fileUpload.getFilename(), charset)+
+                    String replacement = HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+                        HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" +
+                        encodeAttribute(fileUpload.getName(), charset) + "\"\r\n";
+                    replacement += HttpHeaders.Names.CONTENT_TYPE + ": " +
+                        HttpPostBodyUtil.MULTIPART_MIXED + "; " + HttpHeaders.Values.BOUNDARY +
+                        "=" + multipartMixedBoundary + "\r\n\r\n";
+                    replacement += "--" + multipartMixedBoundary + "\r\n";
+                    replacement += HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+                        HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" +
+                        encodeAttribute(fileUpload.getFilename(), charset) +
                         "\"\r\n";
                     pastAttribute.setValue(replacement, 1);
                     // update past size
@@ -510,51 +509,51 @@ public class HttpPostRequestEncoder implements ChunkedInput {
             if (localMixed) {
                 // add mixedmultipart delimiter, mixedmultipart body header and
                 // Data to multipart list
-                internal.addValue("--"+multipartMixedBoundary+"\r\n");
+                internal.addValue("--" + multipartMixedBoundary + "\r\n");
                 // Content-Disposition: file; filename="file1.txt"
-                internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-                        HttpPostBodyUtil.FILE+"; "+HttpPostBodyUtil.FILENAME+"=\""+
-                        encodeAttribute(fileUpload.getFilename(), charset)+
+                internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+                        HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" +
+                        encodeAttribute(fileUpload.getFilename(), charset) +
                         "\"\r\n");
 
             } else {
-                internal.addValue("--"+multipartDataBoundary+"\r\n");
+                internal.addValue("--" + multipartDataBoundary + "\r\n");
                 // Content-Disposition: form-data; name="files"; filename="file1.txt"
-                internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-                        HttpPostBodyUtil.FORM_DATA+"; "+HttpPostBodyUtil.NAME+"=\""+
-                        encodeAttribute(fileUpload.getName(), charset)+"\"; "+
-                        HttpPostBodyUtil.FILENAME+"=\""+
-                        encodeAttribute(fileUpload.getFilename(), charset)+
+                internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+                        HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" +
+                        encodeAttribute(fileUpload.getName(), charset) + "\"; " +
+                        HttpPostBodyUtil.FILENAME + "=\"" +
+                        encodeAttribute(fileUpload.getFilename(), charset) +
                         "\"\r\n");
             }
             // Content-Type: image/gif
             // Content-Type: text/plain; charset=ISO-8859-1
             // Content-Transfer-Encoding: binary
-            internal.addValue(HttpHeaders.Names.CONTENT_TYPE+": "+
+            internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " +
                     fileUpload.getContentType());
             String contentTransferEncoding = fileUpload.getContentTransferEncoding();
             if (contentTransferEncoding != null &&
                     contentTransferEncoding.equals(
                             HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value)) {
-                internal.addValue("\r\n"+HttpHeaders.Names.CONTENT_TRANSFER_ENCODING+
-                        ": "+HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value+
+                internal.addValue("\r\n" + HttpHeaders.Names.CONTENT_TRANSFER_ENCODING +
+                        ": " + HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value +
                         "\r\n\r\n");
             } else if (fileUpload.getCharset() != null) {
-                internal.addValue("; "+HttpHeaders.Values.CHARSET+"="+
-                        fileUpload.getCharset()+"\r\n\r\n");
+                internal.addValue("; " + HttpHeaders.Values.CHARSET + "=" +
+                        fileUpload.getCharset() + "\r\n\r\n");
             } else {
                 internal.addValue("\r\n\r\n");
             }
             multipartHttpDatas.add(internal);
             multipartHttpDatas.add(data);
-            globalBodySize += fileUpload.length()+internal.size();
+            globalBodySize += fileUpload.length() + internal.size();
         }
     }
 
     /**
      * Iterator to be used when encoding will be called chunk after chunk
      */
-    private ListIterator iterator = null;
+    private ListIterator iterator;
 
     /**
      * Finalize the request by preparing the Header in the request and
@@ -573,9 +572,9 @@ public class HttpPostRequestEncoder implements ChunkedInput {
             if (isMultipart) {
                 InternalAttribute internal = new InternalAttribute();
                 if (duringMixedMode) {
-                    internal.addValue("\r\n--"+multipartMixedBoundary+"--");
+                    internal.addValue("\r\n--" + multipartMixedBoundary + "--");
                 }
-                internal.addValue("\r\n--"+multipartDataBoundary+"--\r\n");
+                internal.addValue("\r\n--" + multipartDataBoundary + "--\r\n");
                 multipartHttpDatas.add(internal);
                 multipartMixedBoundary = null;
                 currentFileUpload = null;
@@ -597,7 +596,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                         HttpHeaders.Values.MULTIPART_FORM_DATA)) {
                     // ignore
                 } else if (contentType.toLowerCase().startsWith(
-                        HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)){
+                        HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
                     // ignore
                 } else {
                     request.addHeader(HttpHeaders.Names.CONTENT_TYPE, contentType);
@@ -675,11 +674,11 @@ public class HttpPostRequestEncoder implements ChunkedInput {
     /**
      * The ChannelBuffer currently used by the encoder
      */
-    private ChannelBuffer currentBuffer = null;
+    private ChannelBuffer currentBuffer;
     /**
      * The current InterfaceHttpData to encode (used if more chunks are available)
      */
-    private InterfaceHttpData currentData = null;
+    private InterfaceHttpData currentData;
     /**
      * If not multipart, does the currentBuffer stands for the Key or for the Value
      */
@@ -787,12 +786,12 @@ public class HttpPostRequestEncoder implements ChunkedInput {
                 currentBuffer = ChannelBuffers.wrappedBuffer(
                         buffer, ChannelBuffers.wrappedBuffer("=".getBytes()));
                 //continue
-                size -= buffer.readableBytes()+1;
+                size -= buffer.readableBytes() + 1;
             } else {
                 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
                     buffer, ChannelBuffers.wrappedBuffer("=".getBytes()));
                 //continue
-                size -= buffer.readableBytes()+1;
+                size -= buffer.readableBytes() + 1;
             }
             if (currentBuffer.readableBytes() >= HttpPostBodyUtil.chunkSize) {
                 buffer = fillChannelBuffer();
diff --git a/src/main/java/io/netty/handler/codec/http/HttpRequest.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequest.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpRequest.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpRequest.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java
index ff6897b450..9d2d0665d1 100644
--- a/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestDecoder.java
@@ -71,7 +71,7 @@ public class HttpRequestDecoder extends HttpMessageDecoder {
     }
 
     @Override
-    protected HttpMessage createMessage(String[] initialLine) throws Exception{
+    protected HttpMessage createMessage(String[] initialLine) throws Exception {
         return new DefaultHttpRequest(
                 HttpVersion.valueOf(initialLine[2]), HttpMethod.valueOf(initialLine[0]), initialLine[1]);
     }
diff --git a/src/main/java/io/netty/handler/codec/http/HttpRequestEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpRequestEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpRequestEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpResponse.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponse.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpResponse.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpResponse.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpResponseEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpResponseEncoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpResponseStatus.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpServerCodec.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpServerCodec.java
diff --git a/src/main/java/io/netty/handler/codec/http/HttpVersion.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpVersion.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/HttpVersion.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/HttpVersion.java
diff --git a/src/main/java/io/netty/handler/codec/http/InterfaceHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/InterfaceHttpData.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/InterfaceHttpData.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/InterfaceHttpData.java
diff --git a/src/main/java/io/netty/handler/codec/http/InternalAttribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/InternalAttribute.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/http/InternalAttribute.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/InternalAttribute.java
diff --git a/src/main/java/io/netty/handler/codec/http/MemoryAttribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/MemoryAttribute.java
similarity index 95%
rename from src/main/java/io/netty/handler/codec/http/MemoryAttribute.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/MemoryAttribute.java
index 93881613e7..0a9bfb8c53 100644
--- a/src/main/java/io/netty/handler/codec/http/MemoryAttribute.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/MemoryAttribute.java
@@ -36,8 +36,7 @@ public class MemoryAttribute extends AbstractMemoryHttpData implements Attribute
      * @throws IllegalArgumentException
      * @throws IOException
      */
-    public MemoryAttribute(String name, String value)
-            throws NullPointerException, IllegalArgumentException, IOException {
+    public MemoryAttribute(String name, String value) throws IOException {
         super(name, HttpCodecUtil.DEFAULT_CHARSET, 0); // Attribute have no default size
         setValue(value);
     }
diff --git a/src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java b/codec-http/src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java
similarity index 83%
rename from src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java
index f3f2509d81..0f5d911705 100644
--- a/src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/MemoryFileUpload.java
@@ -24,15 +24,14 @@ import java.nio.charset.Charset;
  */
 public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUpload {
 
-    private String filename = null;
+    private String filename;
 
-    private String contentType = null;
+    private String contentType;
 
-    private String contentTransferEncoding = null;
+    private String contentTransferEncoding;
 
     public MemoryFileUpload(String name, String filename, String contentType,
-            String contentTransferEncoding, Charset charset, long size)
-            throws NullPointerException, IllegalArgumentException {
+            String contentTransferEncoding, Charset charset, long size) {
         super(name, charset, size);
         setFilename(filename);
         setContentType(contentType);
@@ -115,12 +114,12 @@ public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUplo
 
     @Override
     public String toString() {
-        return HttpPostBodyUtil.CONTENT_DISPOSITION+": "+
-            HttpPostBodyUtil.FORM_DATA+"; "+HttpPostBodyUtil.NAME+"=\"" + getName() +
-            "\"; "+HttpPostBodyUtil.FILENAME+"=\"" + filename + "\"\r\n" +
-            HttpHeaders.Names.CONTENT_TYPE+": " + contentType +
-            (charset != null? "; "+HttpHeaders.Values.CHARSET+"=" + charset + "\r\n" : "\r\n") +
-            HttpHeaders.Names.CONTENT_LENGTH+": " + length() + "\r\n" +
+        return HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
+            HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" + getName() +
+            "\"; " + HttpPostBodyUtil.FILENAME + "=\"" + filename + "\"\r\n" +
+            HttpHeaders.Names.CONTENT_TYPE + ": " + contentType +
+            (charset != null? "; " + HttpHeaders.Values.CHARSET + "=" + charset + "\r\n" : "\r\n") +
+            HttpHeaders.Names.CONTENT_LENGTH + ": " + length() + "\r\n" +
             "Completed: " + isCompleted() +
             "\r\nIsInMemory: " + isInMemory();
     }
diff --git a/src/main/java/io/netty/handler/codec/http/MixedAttribute.java b/codec-http/src/main/java/io/netty/handler/codec/http/MixedAttribute.java
similarity index 92%
rename from src/main/java/io/netty/handler/codec/http/MixedAttribute.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/MixedAttribute.java
index 045a39c395..5aa301037c 100644
--- a/src/main/java/io/netty/handler/codec/http/MixedAttribute.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/MixedAttribute.java
@@ -26,20 +26,16 @@ import io.netty.buffer.ChannelBuffer;
  * Mixed implementation using both in Memory and in File with a limit of size
  */
 public class MixedAttribute implements Attribute {
-    private Attribute attribute = null;
+    private Attribute attribute;
 
-    private long limitSize = 0;
+    private long limitSize;
 
-    public MixedAttribute(String name,
-            long limitSize) throws NullPointerException,
-            IllegalArgumentException {
+    public MixedAttribute(String name, long limitSize) {
         this.limitSize = limitSize;
         attribute = new MemoryAttribute(name);
     }
 
-    public MixedAttribute(String name, String value,
-            long limitSize) throws NullPointerException,
-            IllegalArgumentException {
+    public MixedAttribute(String name, String value, long limitSize) {
         this.limitSize = limitSize;
         if (value.length() > this.limitSize) {
             try {
@@ -62,8 +58,7 @@ public class MixedAttribute implements Attribute {
     }
 
     @Override
-    public void addContent(ChannelBuffer buffer, boolean last)
-            throws IOException {
+    public void addContent(ChannelBuffer buffer, boolean last) throws IOException {
         if (attribute instanceof MemoryAttribute) {
             if (attribute.length() + buffer.readableBytes() > limitSize) {
                 DiskAttribute diskAttribute = new DiskAttribute(attribute
diff --git a/src/main/java/io/netty/handler/codec/http/MixedFileUpload.java b/codec-http/src/main/java/io/netty/handler/codec/http/MixedFileUpload.java
similarity index 96%
rename from src/main/java/io/netty/handler/codec/http/MixedFileUpload.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/MixedFileUpload.java
index b98c9375f9..6f0146cb37 100644
--- a/src/main/java/io/netty/handler/codec/http/MixedFileUpload.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/MixedFileUpload.java
@@ -26,16 +26,15 @@ import io.netty.buffer.ChannelBuffer;
  * Mixed implementation using both in Memory and in File with a limit of size
  */
 public class MixedFileUpload implements FileUpload {
-    private FileUpload fileUpload = null;
+    private FileUpload fileUpload;
 
-    private long limitSize = 0;
+    private long limitSize;
 
-    private long definedSize = 0;
+    private long definedSize;
 
     public MixedFileUpload(String name, String filename, String contentType,
             String contentTransferEncoding, Charset charset, long size,
-            long limitSize) throws NullPointerException,
-            IllegalArgumentException {
+            long limitSize) {
         this.limitSize = limitSize;
         if (size > this.limitSize) {
             fileUpload = new DiskFileUpload(name, filename, contentType,
@@ -57,7 +56,7 @@ public class MixedFileUpload implements FileUpload {
                         .getContentType(), fileUpload
                         .getContentTransferEncoding(), fileUpload.getCharset(),
                         definedSize);
-                if (((MemoryFileUpload) fileUpload).getChannelBuffer() != null){
+                if (((MemoryFileUpload) fileUpload).getChannelBuffer() != null) {
                     diskFileUpload.addContent(((MemoryFileUpload) fileUpload)
                         .getChannelBuffer(), last);
                 }
diff --git a/src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java
similarity index 70%
rename from src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java
rename to codec-http/src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java
index 6c89639c0d..d78198f273 100644
--- a/src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/QueryStringDecoder.java
@@ -32,10 +32,25 @@ import io.netty.util.CharsetUtil;
  * 
  * {@link QueryStringDecoder} decoder = new {@link QueryStringDecoder}("/hello?recipient=world&x=1;y=2");
  * assert decoder.getPath().equals("/hello");
- * assert decoder.getParameters().get("recipient").equals("world");
- * assert decoder.getParameters().get("x").equals("1");
- * assert decoder.getParameters().get("y").equals("2");
+ * assert decoder.getParameters().get("recipient").get(0).equals("world");
+ * assert decoder.getParameters().get("x").get(0).equals("1");
+ * assert decoder.getParameters().get("y").get(0).equals("2");
  * 
+ * + * This decoder can also decode the content of an HTTP POST request whose + * content type is application/x-www-form-urlencoded: + *
+ * {@link QueryStringDecoder} decoder = new {@link QueryStringDecoder}("recipient=world&x=1;y=2", false);
+ * ...
+ * 
+ * + *

HashDOS vulnerability fix

+ * + * As a workaround to the HashDOS + * vulnerability, the decoder limits the maximum number of decoded key-value + * parameter pairs, up to {@literal 1024} by default, and you can configure it + * when you construct the decoder by passing an additional integer parameter. + * * @see QueryStringEncoder * * @apiviz.stereotype utility @@ -43,10 +58,15 @@ import io.netty.util.CharsetUtil; */ public class QueryStringDecoder { + private static final int DEFAULT_MAX_PARAMS = 1024; + private final Charset charset; private final String uri; + private final boolean hasPath; + private final int maxParams; private String path; private Map> params; + private int nParams; /** * Creates a new decoder that decodes the specified URI. The decoder will @@ -56,21 +76,51 @@ public class QueryStringDecoder { this(uri, HttpCodecUtil.DEFAULT_CHARSET); } + /** + * Creates a new decoder that decodes the specified URI encoded in the + * specified charset. + */ + public QueryStringDecoder(String uri, boolean hasPath) { + this(uri, HttpCodecUtil.DEFAULT_CHARSET, hasPath); + } + /** * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ public QueryStringDecoder(String uri, Charset charset) { + this(uri, charset, true); + } + + /** + * Creates a new decoder that decodes the specified URI encoded in the + * specified charset. + */ + public QueryStringDecoder(String uri, Charset charset, boolean hasPath) { + this(uri, charset, hasPath, DEFAULT_MAX_PARAMS); + } + + /** + * Creates a new decoder that decodes the specified URI encoded in the + * specified charset. + */ + public QueryStringDecoder(String uri, Charset charset, boolean hasPath, int maxParams) { if (uri == null) { throw new NullPointerException("uri"); } if (charset == null) { throw new NullPointerException("charset"); } + if (maxParams <= 0) { + throw new IllegalArgumentException( + "maxParams: " + maxParams + " (expected: a positive integer)"); + } // http://en.wikipedia.org/wiki/Query_string this.uri = uri.replace(';', '&'); this.charset = charset; + this.maxParams = maxParams; + this.hasPath = hasPath; } /** @@ -85,17 +135,31 @@ public class QueryStringDecoder { * Creates a new decoder that decodes the specified URI encoded in the * specified charset. */ - public QueryStringDecoder(URI uri, Charset charset){ + public QueryStringDecoder(URI uri, Charset charset) { + this(uri, charset, DEFAULT_MAX_PARAMS); + } + + /** + * Creates a new decoder that decodes the specified URI encoded in the + * specified charset. + */ + public QueryStringDecoder(URI uri, Charset charset, int maxParams) { if (uri == null) { throw new NullPointerException("uri"); } if (charset == null) { throw new NullPointerException("charset"); } + if (maxParams <= 0) { + throw new IllegalArgumentException( + "maxParams: " + maxParams + " (expected: a positive integer)"); + } // http://en.wikipedia.org/wiki/Query_string this.uri = uri.toASCIIString().replace(';', '&'); this.charset = charset; + this.maxParams = maxParams; + hasPath = false; } /** @@ -103,11 +167,14 @@ public class QueryStringDecoder { */ public String getPath() { if (path == null) { + if (!hasPath) { + return path = ""; + } + int pathEndPos = uri.indexOf('?'); if (pathEndPos < 0) { path = uri; - } - else { + } else { return path = uri.substring(0, pathEndPos); } } @@ -119,17 +186,25 @@ public class QueryStringDecoder { */ public Map> getParameters() { if (params == null) { - int pathLength = getPath().length(); - if (uri.length() == pathLength) { - return Collections.emptyMap(); + if (hasPath) { + int pathLength = getPath().length(); + if (uri.length() == pathLength) { + return Collections.emptyMap(); + } + decodeParams(uri.substring(pathLength + 1)); + } else { + if (uri.isEmpty()) { + return Collections.emptyMap(); + } + decodeParams(uri); } - params = decodeParams(uri.substring(pathLength + 1)); } return params; } - private Map> decodeParams(String s) { - Map> params = new LinkedHashMap>(); + private void decodeParams(String s) { + Map> params = this.params = new LinkedHashMap>(); + nParams = 0; String name = null; int pos = 0; // Beginning of the unprocessed region int i; // End of the unprocessed region @@ -146,9 +221,13 @@ public class QueryStringDecoder { // We haven't seen an `=' so far but moved forward. // Must be a param of the form '&a&' so add it with // an empty value. - addParam(params, decodeComponent(s.substring(pos, i), charset), ""); + if (!addParam(params, decodeComponent(s.substring(pos, i), charset), "")) { + return; + } } else if (name != null) { - addParam(params, name, decodeComponent(s.substring(pos, i), charset)); + if (!addParam(params, name, decodeComponent(s.substring(pos, i), charset))) { + return; + } name = null; } pos = i + 1; @@ -157,15 +236,34 @@ public class QueryStringDecoder { if (pos != i) { // Are there characters we haven't dealt with? if (name == null) { // Yes and we haven't seen any `='. - addParam(params, decodeComponent(s.substring(pos, i), charset), ""); + if (!addParam(params, decodeComponent(s.substring(pos, i), charset), "")) { + return; + } } else { // Yes and this must be the last value. - addParam(params, name, decodeComponent(s.substring(pos, i), charset)); + if (!addParam(params, name, decodeComponent(s.substring(pos, i), charset))) { + return; + } } } else if (name != null) { // Have we seen a name without value? - addParam(params, name, ""); + if (!addParam(params, name, "")) { + return; + } + } + } + + private boolean addParam(Map> params, String name, String value) { + if (nParams >= maxParams) { + return false; } - return params; + List values = params.get(name); + if (values == null) { + values = new ArrayList(1); // Often there's only 1 value. + params.put(name, values); + } + values.add(value); + nParams ++; + return true; } /** @@ -284,13 +382,4 @@ public class QueryStringDecoder { return Character.MAX_VALUE; } } - - private static void addParam(Map> params, String name, String value) { - List values = params.get(name); - if (values == null) { - values = new ArrayList(1); // Often there's only 1 value. - params.put(name, values); - } - values.add(value); - } } diff --git a/src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java similarity index 97% rename from src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java index e96f6e6cdf..cf1211c806 100644 --- a/src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/QueryStringEncoder.java @@ -29,7 +29,7 @@ import java.util.List; * This encoder is for one time use only. Create a new instance for each URI. * *
- * {@link QueryStringEncoder} encoder = new {@link QueryStringDecoder}("/hello");
+ * {@link QueryStringEncoder} encoder = new {@link QueryStringEncoder}("/hello");
  * encoder.addParam("recipient", "world");
  * assert encoder.toString().equals("/hello?recipient=world");
  * 
@@ -106,7 +106,7 @@ public class QueryStringEncoder { sb.append(encodeComponent(param.name, charset)); sb.append("="); sb.append(encodeComponent(param.value, charset)); - if(i != params.size() - 1) { + if (i != params.size() - 1) { sb.append("&"); } } diff --git a/src/main/java/io/netty/handler/codec/http/package-info.java b/codec-http/src/main/java/io/netty/handler/codec/http/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/http/package-info.java rename to codec-http/src/main/java/io/netty/handler/codec/http/package-info.java diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java similarity index 85% rename from src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java index a05669647a..983879e980 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/BinaryWebSocketFrame.java @@ -27,23 +27,21 @@ public class BinaryWebSocketFrame extends WebSocketFrame { * Creates a new empty binary frame. */ public BinaryWebSocketFrame() { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** - * Creates a new binary frame with the specified binary data. The final - * fragment flag is set to true. + * Creates a new binary frame with the specified binary data. The final fragment flag is set to true. * * @param binaryData * the content of the frame. */ public BinaryWebSocketFrame(ChannelBuffer binaryData) { - this.setBinaryData(binaryData); + setBinaryData(binaryData); } /** - * Creates a new binary frame with the specified binary data and the final - * fragment flag. + * Creates a new binary frame with the specified binary data and the final fragment flag. * * @param finalFragment * flag indicating if this frame is the final fragment @@ -53,9 +51,9 @@ public class BinaryWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public BinaryWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); } @Override diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java similarity index 91% rename from src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java index 67a61f8199..1f8ed46028 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java @@ -26,7 +26,7 @@ public class CloseWebSocketFrame extends WebSocketFrame { * Creates a new empty close frame. */ public CloseWebSocketFrame() { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** @@ -38,8 +38,8 @@ public class CloseWebSocketFrame extends WebSocketFrame { * reserved bits used for protocol extensions */ public CloseWebSocketFrame(boolean finalFragment, int rsv) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); + setFinalFragment(finalFragment); + setRsv(rsv); } @Override diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java similarity index 77% rename from src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java index 6e647e011b..cb373dabe6 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/ContinuationWebSocketFrame.java @@ -20,30 +20,28 @@ import io.netty.buffer.ChannelBuffers; import io.netty.util.CharsetUtil; /** - * Web Socket continuation frame containing continuation text or binary data. - * This is used for fragmented messages where the contents of a messages is - * contained more than 1 frame. + * Web Socket continuation frame containing continuation text or binary data. This is used for fragmented messages where + * the contents of a messages is contained more than 1 frame. */ public class ContinuationWebSocketFrame extends WebSocketFrame { - private String aggregatedText = null; + private String aggregatedText; /** * Creates a new empty continuation frame. */ public ContinuationWebSocketFrame() { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** - * Creates a new continuation frame with the specified binary data. The - * final fragment flag is set to true. + * Creates a new continuation frame with the specified binary data. The final fragment flag is set to true. * * @param binaryData * the content of the frame. */ public ContinuationWebSocketFrame(ChannelBuffer binaryData) { - this.setBinaryData(binaryData); + setBinaryData(binaryData); } /** @@ -57,9 +55,9 @@ public class ContinuationWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); } /** @@ -72,13 +70,12 @@ public class ContinuationWebSocketFrame extends WebSocketFrame { * @param binaryData * the content of the frame. * @param aggregatedText - * Aggregated text set by decoder on the final continuation frame - * of a fragmented text message + * Aggregated text set by decoder on the final continuation frame of a fragmented text message */ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData, String aggregatedText) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); this.aggregatedText = aggregatedText; } @@ -93,19 +90,19 @@ public class ContinuationWebSocketFrame extends WebSocketFrame { * text content of the frame. */ public ContinuationWebSocketFrame(boolean finalFragment, int rsv, String text) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setText(text); + setFinalFragment(finalFragment); + setRsv(rsv); + setText(text); } /** * Returns the text data in this frame */ public String getText() { - if (this.getBinaryData() == null) { + if (getBinaryData() == null) { return null; } - return this.getBinaryData().toString(CharsetUtil.UTF_8); + return getBinaryData().toString(CharsetUtil.UTF_8); } /** @@ -116,9 +113,9 @@ public class ContinuationWebSocketFrame extends WebSocketFrame { */ public void setText(String text) { if (text == null || text.isEmpty()) { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { - this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); + setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } @@ -128,8 +125,7 @@ public class ContinuationWebSocketFrame extends WebSocketFrame { } /** - * Aggregated text returned by decoder on the final continuation frame of a - * fragmented text message + * Aggregated text returned by decoder on the final continuation frame of a fragmented text message */ public String getAggregatedText() { return aggregatedText; diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java similarity index 87% rename from src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java index 5815faad97..0923e1fb47 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PingWebSocketFrame.java @@ -27,8 +27,8 @@ public class PingWebSocketFrame extends WebSocketFrame { * Creates a new empty ping frame. */ public PingWebSocketFrame() { - this.setFinalFragment(true); - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setFinalFragment(true); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** @@ -38,7 +38,7 @@ public class PingWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public PingWebSocketFrame(ChannelBuffer binaryData) { - this.setBinaryData(binaryData); + setBinaryData(binaryData); } /** @@ -52,9 +52,9 @@ public class PingWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public PingWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); } @Override diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java similarity index 89% rename from src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java index ee3fd861b4..8cd3eb51ab 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/PongWebSocketFrame.java @@ -27,7 +27,7 @@ public class PongWebSocketFrame extends WebSocketFrame { * Creates a new empty pong frame. */ public PongWebSocketFrame() { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** @@ -37,7 +37,7 @@ public class PongWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public PongWebSocketFrame(ChannelBuffer binaryData) { - this.setBinaryData(binaryData); + setBinaryData(binaryData); } /** @@ -51,9 +51,9 @@ public class PongWebSocketFrame extends WebSocketFrame { * the content of the frame. */ public PongWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); } @Override diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java similarity index 75% rename from src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java index 18aeabc66e..a9f89e6518 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/TextWebSocketFrame.java @@ -28,38 +28,35 @@ public class TextWebSocketFrame extends WebSocketFrame { * Creates a new empty text frame. */ public TextWebSocketFrame() { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } /** - * Creates a new text frame with the specified text string. The final - * fragment flag is set to true. + * Creates a new text frame with the specified text string. The final fragment flag is set to true. * * @param text * String to put in the frame */ public TextWebSocketFrame(String text) { if (text == null || text.isEmpty()) { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { - this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); + setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } /** - * Creates a new text frame with the specified binary data. The final - * fragment flag is set to true. + * Creates a new text frame with the specified binary data. The final fragment flag is set to true. * * @param binaryData * the content of the frame. Must be UTF-8 encoded */ public TextWebSocketFrame(ChannelBuffer binaryData) { - this.setBinaryData(binaryData); + setBinaryData(binaryData); } /** - * Creates a new text frame with the specified text string. The final - * fragment flag is set to true. + * Creates a new text frame with the specified text string. The final fragment flag is set to true. * * @param finalFragment * flag indicating if this frame is the final fragment @@ -69,18 +66,17 @@ public class TextWebSocketFrame extends WebSocketFrame { * String to put in the frame */ public TextWebSocketFrame(boolean finalFragment, int rsv, String text) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); + setFinalFragment(finalFragment); + setRsv(rsv); if (text == null || text.isEmpty()) { - this.setBinaryData(ChannelBuffers.EMPTY_BUFFER); + setBinaryData(ChannelBuffers.EMPTY_BUFFER); } else { - this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); + setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } } /** - * Creates a new text frame with the specified binary data. The final - * fragment flag is set to true. + * Creates a new text frame with the specified binary data. The final fragment flag is set to true. * * @param finalFragment * flag indicating if this frame is the final fragment @@ -90,19 +86,19 @@ public class TextWebSocketFrame extends WebSocketFrame { * the content of the frame. Must be UTF-8 encoded */ public TextWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { - this.setFinalFragment(finalFragment); - this.setRsv(rsv); - this.setBinaryData(binaryData); + setFinalFragment(finalFragment); + setRsv(rsv); + setBinaryData(binaryData); } /** * Returns the text data in this frame */ public String getText() { - if (this.getBinaryData() == null) { + if (getBinaryData() == null) { return null; } - return this.getBinaryData().toString(CharsetUtil.UTF_8); + return getBinaryData().toString(CharsetUtil.UTF_8); } /** @@ -115,7 +111,7 @@ public class TextWebSocketFrame extends WebSocketFrame { if (text == null) { throw new NullPointerException("text"); } - this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); + setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8)); } @Override diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java similarity index 70% rename from src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java index 9b1eaae803..9ff63cb9a9 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Exception.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ /* * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ * diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java similarity index 56% rename from src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java index 443afdfc99..eabccdc6b8 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/UTF8Output.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ /* * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ * @@ -26,15 +41,23 @@ final class UTF8Output { private static final int UTF8_ACCEPT = 0; private static final int UTF8_REJECT = 12; - private static final byte[] TYPES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; + private static final byte[] TYPES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, + 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; - private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, - 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; + private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12 }; private int state = UTF8_ACCEPT; - private int codep = 0; + private int codep; private final StringBuilder stringBuilder; @@ -52,7 +75,7 @@ final class UTF8Output { public void write(int b) { byte type = TYPES[b & 0xFF]; - codep = (state != UTF8_ACCEPT) ? (b & 0x3f) | (codep << 6) : (0xff >> type) & (b); + codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b; state = STATES[state + type]; diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java similarity index 86% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java index a0b37ffe9a..69ca9776cf 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameDecoder.java @@ -25,15 +25,15 @@ import io.netty.handler.codec.replay.VoidEnum; /** * Decodes {@link ChannelBuffer}s into {@link WebSocketFrame}s. *

- * For the detailed instruction on adding add Web Socket support to your HTTP - * server, take a look into the WebSocketServer example located in the - * {@code io.netty.example.http.websocket} package. + * For the detailed instruction on adding add Web Socket support to your HTTP server, take a look into the + * WebSocketServer example located in the {@code io.netty.example.http.websocket} package. + * * @apiviz.landmark * @apiviz.uses io.netty.handler.codec.http.websocket.WebSocketFrame */ public class WebSocket00FrameDecoder extends ReplayingDecoder { - public static final int DEFAULT_MAX_FRAME_SIZE = 16384; + private static final int DEFAULT_MAX_FRAME_SIZE = 16384; private final int maxFrameSize; private boolean receivedClosingHandshake; @@ -43,9 +43,8 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { } /** - * Creates a new instance of {@code WebSocketFrameDecoder} with the - * specified {@code maxFrameSize}. If the client sends a frame size larger - * than {@code maxFrameSize}, the channel will be closed. + * Creates a new instance of {@code WebSocketFrameDecoder} with the specified {@code maxFrameSize}. If the client + * sends a frame size larger than {@code maxFrameSize}, the channel will be closed. * * @param maxFrameSize * the maximum frame size to decode @@ -55,7 +54,8 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { } @Override - protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) throws Exception { + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, VoidEnum state) + throws Exception { // Discard all data received if closing handshake was received before. if (receivedClosingHandshake) { @@ -70,7 +70,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { return decodeBinaryFrame(type, buffer); } else { // Decode a 0xff terminated UTF-8 string - return decodeTextFrame(type, buffer); + return decodeTextFrame(buffer); } } @@ -92,7 +92,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { } } while ((b & 0x80) == 0x80); - if (type == ((byte) 0xFF) && frameSize == 0) { + if (type == (byte) 0xFF && frameSize == 0) { receivedClosingHandshake = true; return new CloseWebSocketFrame(); } @@ -100,7 +100,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder { return new BinaryWebSocketFrame(buffer.readBytes((int) frameSize)); } - private WebSocketFrame decodeTextFrame(byte type, ChannelBuffer buffer) throws TooLongFrameException { + private WebSocketFrame decodeTextFrame(ChannelBuffer buffer) throws TooLongFrameException { int ridx = buffer.readerIndex(); int rbytes = actualReadableBytes(); int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF); diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java similarity index 94% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java index ca49ea4f04..ea0d36feb6 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket00FrameEncoder.java @@ -24,9 +24,9 @@ import io.netty.handler.codec.oneone.OneToOneEncoder; /** * Encodes a {@link WebSocketFrame} into a {@link ChannelBuffer}. *

- * For the detailed instruction on adding add Web Socket support to your HTTP - * server, take a look into the WebSocketServer example located in the - * {@code io.netty.example.http.websocket} package. + * For the detailed instruction on adding add Web Socket support to your HTTP server, take a look into the + * WebSocketServer example located in the {@code io.netty.example.http.websocket} package. + * * @apiviz.landmark * @apiviz.uses io.netty.handler.codec.http.websocket.WebSocketFrame */ @@ -40,7 +40,8 @@ public class WebSocket00FrameEncoder extends OneToOneEncoder { if (frame instanceof TextWebSocketFrame) { // Text frame ChannelBuffer data = frame.getBinaryData(); - ChannelBuffer encoded = channel.getConfig().getBufferFactory().getBuffer(data.order(), data.readableBytes() + 2); + ChannelBuffer encoded = channel.getConfig().getBufferFactory() + .getBuffer(data.order(), data.readableBytes() + 2); encoded.writeByte((byte) 0x00); encoded.writeBytes(data, data.readerIndex(), data.readableBytes()); encoded.writeByte((byte) 0xFF); diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java similarity index 91% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java index 78fcd0a2c6..5bd7ea0038 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors @@ -50,9 +65,8 @@ import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; /** - * Decodes a web socket frame from wire protocol version 8 format. This code was - * forked from webbit and - * modified. + * Decodes a web socket frame from wire protocol version 8 format. This code was forked from webbit and modified. */ public class WebSocket08FrameDecoder extends ReplayingDecoder { @@ -65,20 +79,20 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder> 4; - frameOpcode = (b & 0x0F); + frameOpcode = b & 0x0F; if (logger.isDebugEnabled()) { logger.debug("Decoding WebSocket Frame opCode=" + frameOpcode); @@ -128,14 +142,14 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder - * Encodes a web socket frame into wire protocol version 8 format. This code was - * forked from webbit and - * modified. + * Encodes a web socket frame into wire protocol version 8 format. This code was forked from webbit and modified. *

*/ public class WebSocket08FrameEncoder extends OneToOneEncoder { @@ -67,14 +81,14 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder { private static final byte OPCODE_PING = 0x9; private static final byte OPCODE_PONG = 0xA; - private boolean maskPayload = false; + private final boolean maskPayload; /** * Constructor * * @param maskPayload - * Web socket clients must set this to true to mask payload. - * Server implementations must set this to false. + * Web socket clients must set this to true to mask payload. Server implementations must set this to + * false. */ public WebSocket08FrameEncoder(boolean maskPayload) { this.maskPayload = maskPayload; @@ -83,7 +97,7 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder { @Override protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception { - byte[] mask = null; + byte[] mask; if (msg instanceof WebSocketFrame) { WebSocketFrame frame = (WebSocketFrame) msg; @@ -112,44 +126,45 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder { int length = data.readableBytes(); if (logger.isDebugEnabled()) { - logger.debug("Encoding WebSocket Frame opCode=" + opcode + " length=" + length); + logger.debug("Encoding WebSocket Frame opCode=" + opcode + " length=" + length); } - + int b0 = 0; if (frame.isFinalFragment()) { - b0 |= (1 << 7); + b0 |= 1 << 7; } - b0 |= (frame.getRsv() % 8) << 4; + b0 |= frame.getRsv() % 8 << 4; b0 |= opcode % 128; ChannelBuffer header; ChannelBuffer body; if (opcode == OPCODE_PING && length > 125) { - throw new TooLongFrameException("invalid payload for PING (payload length must be <= 125, was " + length); + throw new TooLongFrameException("invalid payload for PING (payload length must be <= 125, was " + + length); } - int maskLength = this.maskPayload ? 4 : 0; + int maskLength = maskPayload ? 4 : 0; if (length <= 125) { header = ChannelBuffers.buffer(2 + maskLength); header.writeByte(b0); - byte b = (byte) (this.maskPayload ? (0x80 | (byte) length) : (byte) length); + byte b = (byte) (maskPayload ? 0x80 | (byte) length : (byte) length); header.writeByte(b); } else if (length <= 0xFFFF) { header = ChannelBuffers.buffer(4 + maskLength); header.writeByte(b0); - header.writeByte(this.maskPayload ? (0xFE) : 126); - header.writeByte((length >>> 8) & 0xFF); - header.writeByte((length) & 0xFF); + header.writeByte(maskPayload ? 0xFE : 126); + header.writeByte(length >>> 8 & 0xFF); + header.writeByte(length & 0xFF); } else { header = ChannelBuffers.buffer(10 + maskLength); header.writeByte(b0); - header.writeByte(this.maskPayload ? (0xFF) : 127); + header.writeByte(maskPayload ? 0xFF : 127); header.writeLong(length); } // Write payload - if (this.maskPayload) { + if (maskPayload) { Integer random = (int) (Math.random() * Integer.MAX_VALUE); mask = ByteBuffer.allocate(4).putInt(random).array(); header.writeBytes(mask); @@ -170,4 +185,4 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder { return msg; } -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java similarity index 72% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java index b98eb58fa0..6c592c686e 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameDecoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors @@ -39,8 +54,7 @@ package io.netty.handler.codec.http.websocketx; /** - * Decodes a web socket frame from wire protocol version 13 format. - * V13 is essentially the same as V8. + * Decodes a web socket frame from wire protocol version 13 format. V13 is essentially the same as V8. */ public class WebSocket13FrameDecoder extends WebSocket08FrameDecoder { @@ -48,12 +62,12 @@ public class WebSocket13FrameDecoder extends WebSocket08FrameDecoder { * Constructor * * @param maskedPayload - * Web socket servers must set this to true processed incoming - * masked payload. Client implementations must set this to false. + * Web socket servers must set this to true processed incoming masked payload. Client implementations + * must set this to false. * @param allowExtensions * Flag to allow reserved extension bits to be used or not */ public WebSocket13FrameDecoder(boolean maskedPayload, boolean allowExtensions) { - super(maskedPayload, allowExtensions); + super(maskedPayload, allowExtensions); } } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java similarity index 73% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java index a435136639..f0328dc91e 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket13FrameEncoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ // (BSD License: http://www.opensource.org/licenses/bsd-license) // // Copyright (c) 2011, Joe Walnes and contributors @@ -38,11 +53,9 @@ package io.netty.handler.codec.http.websocketx; - /** *

- * Encodes a web socket frame into wire protocol version 13 format. V13 is essentially the same - * as V8. + * Encodes a web socket frame into wire protocol version 13 format. V13 is essentially the same as V8. *

*/ public class WebSocket13FrameEncoder extends WebSocket08FrameEncoder { @@ -51,8 +64,8 @@ public class WebSocket13FrameEncoder extends WebSocket08FrameEncoder { * Constructor * * @param maskPayload - * Web socket clients must set this to true to mask payload. - * Server implementations must set this to false. + * Web socket clients must set this to true to mask payload. Server implementations must set this to + * false. */ public WebSocket13FrameEncoder(boolean maskPayload) { super(maskPayload); diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java new file mode 100644 index 0000000000..18ad9ec051 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java @@ -0,0 +1,129 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import java.net.URI; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Map; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.util.CharsetUtil; + +/** + * Base class for web socket client handshake implementations + */ +public abstract class WebSocketClientHandshaker { + + private final URI webSocketUrl; + + private final WebSocketVersion version; + + private boolean handshakeComplete; + + private final String expectedSubprotocol; + + private String actualSubprotocol; + + protected final Map customHeaders; + + /** + * Base constructor + * + * @param webSocketUrl + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param version + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. + * @param customHeaders + * Map of custom headers to add to the client request + */ + public WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol, + Map customHeaders) { + this.webSocketUrl = webSocketUrl; + this.version = version; + expectedSubprotocol = subprotocol; + this.customHeaders = customHeaders; + } + + /** + * Returns the URI to the web socket. e.g. "ws://myhost.com/path" + */ + public URI getWebSocketUrl() { + return webSocketUrl; + } + + /** + * Version of the web socket specification that is being used + */ + public WebSocketVersion getVersion() { + return version; + } + + /** + * Flag to indicate if the opening handshake is complete + */ + public boolean isHandshakeComplete() { + return handshakeComplete; + } + + protected void setHandshakeComplete() { + handshakeComplete = true; + } + + /** + * Returns the sub protocol request sent to the server as specified in the constructor + */ + public String getExpectedSubprotocol() { + return expectedSubprotocol; + } + + /** + * Returns the sub protocol response and sent by the server. Only available after end of handshake. + */ + public String getActualSubprotocol() { + return actualSubprotocol; + } + + protected void setActualSubprotocol(String actualSubprotocol) { + this.actualSubprotocol = actualSubprotocol; + } + + /** + * Begins the opening handshake + * + * @param channel + * Channel + */ + public abstract ChannelFuture handshake(Channel channel); + + /** + * Validates and finishes the opening handshake initiated by {@link #handshake}}. + * + * @param channel + * Channel + * @param response + * HTTP response containing the closing handshake details + */ + public abstract void finishHandshake(Channel channel, HttpResponse response); +} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java similarity index 75% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java index 3abbf8c201..d4d26e45a6 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker00.java @@ -18,9 +18,11 @@ package io.netty.handler.codec.http.websocketx; import java.net.URI; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Map; import io.netty.buffer.ChannelBuffers; import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Values; @@ -34,10 +36,9 @@ import io.netty.handler.codec.http.HttpVersion; /** *

- * Performs client side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 00 + * Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 00 *

*

* A very large portion of this code was taken from the Netty 3.2 HTTP example. @@ -45,24 +46,25 @@ import io.netty.handler.codec.http.HttpVersion; */ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { - private byte[] expectedChallengeResponseBytes = null; + private byte[] expectedChallengeResponseBytes; /** - * Constructor specifying the destination web socket location and version to - * initiate + * Constructor specifying the destination web socket location and version to initiate * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version - * Version of web socket specification to use to connect to the - * server - * @param subProtocol + * Version of web socket specification to use to connect to the server + * @param subprotocol * Sub protocol request sent to the server. + * @param customHeaders + * Map of custom headers to add to the client request */ - public WebSocketClientHandshaker00(URI webSocketURL, WebSocketSpecificationVersion version, String subProtocol) { - super(webSocketURL, version, subProtocol); + public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol, + Map customHeaders) { + super(webSocketURL, version, subprotocol, customHeaders); + } /** @@ -86,16 +88,16 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { * Channel into which we can write our request */ @Override - public void performOpeningHandshake(Channel channel) { + public ChannelFuture handshake(Channel channel) { // Make keys - int spaces1 = createRandomNumber(1, 12); - int spaces2 = createRandomNumber(1, 12); + int spaces1 = WebSocketUtil.randomNumber(1, 12); + int spaces2 = WebSocketUtil.randomNumber(1, 12); int max1 = Integer.MAX_VALUE / spaces1; int max2 = Integer.MAX_VALUE / spaces2; - int number1 = createRandomNumber(0, max1); - int number2 = createRandomNumber(0, max2); + int number1 = WebSocketUtil.randomNumber(0, max1); + int number2 = WebSocketUtil.randomNumber(0, max2); int product1 = number1 * spaces1; int product2 = number2 * spaces2; @@ -109,7 +111,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { key1 = insertSpaces(key1, spaces1); key2 = insertSpaces(key2, spaces2); - byte[] key3 = createRandomBytes(8); + byte[] key3 = WebSocketUtil.randomBytes(8); ByteBuffer buffer = ByteBuffer.allocate(4); buffer.putInt(number1); @@ -122,10 +124,10 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { System.arraycopy(number1Array, 0, challenge, 0, 4); System.arraycopy(number2Array, 0, challenge, 4, 4); System.arraycopy(key3, 0, challenge, 8, 8); - this.expectedChallengeResponseBytes = md5(challenge); + expectedChallengeResponseBytes = WebSocketUtil.md5(challenge); // Get path - URI wsURL = this.getWebSocketURL(); + URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + "?" + wsURL.getQuery(); @@ -139,14 +141,23 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { request.addHeader(Names.ORIGIN, "http://" + wsURL.getHost()); request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1); request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2); - if (this.getSubProtocolRequest() != null && !this.getSubProtocolRequest().equals("")) { - request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.getSubProtocolRequest()); + if (getExpectedSubprotocol() != null && !getExpectedSubprotocol().equals("")) { + request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, getExpectedSubprotocol()); } + + if (customHeaders != null) { + for (String header : customHeaders.keySet()) { + request.addHeader(header, customHeaders.get(header)); + } + } + request.setContent(ChannelBuffers.copiedBuffer(key3)); - channel.write(request); + ChannelFuture future = channel.write(request); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket00FrameEncoder()); + + return future; } /** @@ -168,12 +179,11 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { * @param channel * Channel * @param response - * HTTP response returned from the server for the request sent by - * beginOpeningHandshake00(). + * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override - public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException { + public void finishHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException { final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake"); if (!response.getStatus().equals(status)) { @@ -182,12 +192,14 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { String upgrade = response.getHeader(Names.UPGRADE); if (upgrade == null || !upgrade.equals(Values.WEBSOCKET)) { - throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.getHeader(Names.UPGRADE)); + throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + + response.getHeader(Names.UPGRADE)); } String connection = response.getHeader(Names.CONNECTION); if (connection == null || !connection.equals(Values.UPGRADE)) { - throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.getHeader(Names.CONNECTION)); + throw new WebSocketHandshakeException("Invalid handshake response connection: " + + response.getHeader(Names.CONNECTION)); } byte[] challenge = response.getContent().array(); @@ -196,28 +208,28 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { } String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); - this.setSubProtocolResponse(protocol); + setActualSubprotocol(protocol); channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket00FrameDecoder()); - this.setOpenningHandshakeCompleted(true); + setHandshakeComplete(); } private String insertRandomCharacters(String key) { - int count = createRandomNumber(1, 12); + int count = WebSocketUtil.randomNumber(1, 12); char[] randomChars = new char[count]; int randCount = 0; while (randCount < count) { int rand = (int) (Math.random() * 0x7e + 0x21); - if (((0x21 < rand) && (rand < 0x2f)) || ((0x3a < rand) && (rand < 0x7e))) { + if (0x21 < rand && rand < 0x2f || 0x3a < rand && rand < 0x7e) { randomChars[randCount] = (char) rand; randCount += 1; } } for (int i = 0; i < count; i++) { - int split = createRandomNumber(0, key.length()); + int split = WebSocketUtil.randomNumber(0, key.length()); String part1 = key.substring(0, split); String part2 = key.substring(split); key = part1 + randomChars[i] + part2; @@ -228,7 +240,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker { private String insertSpaces(String key, int spaces) { for (int i = 0; i < spaces; i++) { - int split = createRandomNumber(1, key.length() - 1); + int split = WebSocketUtil.randomNumber(1, key.length() - 1); String part1 = key.substring(0, split); String part2 = key.substring(split); key = part1 + " " + part2; diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker10.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java similarity index 68% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker10.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java index 1e6fdb1f48..f9d122903a 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker10.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker08.java @@ -16,8 +16,10 @@ package io.netty.handler.codec.http.websocketx; import java.net.URI; +import java.util.Map; import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Values; @@ -34,43 +36,41 @@ import io.netty.util.CharsetUtil; /** *

- * Performs client side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 10 + * Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 10 *

*/ -public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker { +public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker10.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker08.class); public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - private String expectedChallengeResponseString = null; + private String expectedChallengeResponseString; private static final String protocol = null; - private boolean allowExtensions = false; + private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location and version to - * initiate + * Constructor specifying the destination web socket location and version to initiate * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version - * Version of web socket specification to use to connect to the - * server - * @param subProtocol + * Version of web socket specification to use to connect to the server + * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Map of custom headers to add to the client request */ - public WebSocketClientHandshaker10(URI webSocketURL, WebSocketSpecificationVersion version, String subProtocol, boolean allowExtensions) { - super(webSocketURL, version, subProtocol); + public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders) { + super(webSocketURL, version, subprotocol, customHeaders); this.allowExtensions = allowExtensions; } @@ -95,24 +95,25 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker { * Channel into which we can write our request */ @Override - public void performOpeningHandshake(Channel channel) { + public ChannelFuture handshake(Channel channel) { // Get path - URI wsURL = this.getWebSocketURL(); + URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + "?" + wsURL.getQuery(); } // Get 16 bit nonce and base 64 encode it - byte[] nonce = createRandomBytes(16); - String key = base64Encode(nonce); + byte[] nonce = WebSocketUtil.randomBytes(16); + String key = WebSocketUtil.base64(nonce); String acceptSeed = key + MAGIC_GUID; - byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); - this.expectedChallengeResponseString = base64Encode(sha1); + byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); + expectedChallengeResponseString = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { - logger.debug(String.format("HyBi10 Client Handshake key: %s. Expected response: %s.", key, this.expectedChallengeResponseString)); + logger.debug(String.format("WS Version 08 Client Handshake key: %s. Expected response: %s.", key, + expectedChallengeResponseString)); } // Format request @@ -127,9 +128,17 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker { } request.addHeader(Names.SEC_WEBSOCKET_VERSION, "8"); - channel.write(request); + if (customHeaders != null) { + for (String header : customHeaders.keySet()) { + request.addHeader(header, customHeaders.get(header)); + } + } + + ChannelFuture future = channel.write(request); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket08FrameEncoder(true)); + + return future; } /** @@ -148,13 +157,12 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker { * @param channel * Channel * @param response - * HTTP response returned from the server for the request sent by - * beginOpeningHandshake00(). + * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override - public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException { - final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols"); + public void finishHandshake(Channel channel, HttpResponse response) { + final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS; if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); @@ -162,22 +170,25 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker { String upgrade = response.getHeader(Names.UPGRADE); if (upgrade == null || !upgrade.equals(Values.WEBSOCKET.toLowerCase())) { - throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.getHeader(Names.UPGRADE)); + throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + + response.getHeader(Names.UPGRADE)); } String connection = response.getHeader(Names.CONNECTION); if (connection == null || !connection.equals(Values.UPGRADE)) { - throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.getHeader(Names.CONNECTION)); + throw new WebSocketHandshakeException("Invalid handshake response connection: " + + response.getHeader(Names.CONNECTION)); } String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT); - if (accept == null || !accept.equals(this.expectedChallengeResponseString)) { - throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString)); + if (accept == null || !accept.equals(expectedChallengeResponseString)) { + throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, + expectedChallengeResponseString)); } - channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket08FrameDecoder(false, this.allowExtensions)); + channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", + new WebSocket08FrameDecoder(false, allowExtensions)); - this.setOpenningHandshakeCompleted(true); + setHandshakeComplete(); } - } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker17.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java similarity index 67% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker17.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java index 262eb7d40c..19cfd1abbb 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker17.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker13.java @@ -16,8 +16,10 @@ package io.netty.handler.codec.http.websocketx; import java.net.URI; +import java.util.Map; import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Values; @@ -34,43 +36,41 @@ import io.netty.util.CharsetUtil; /** *

- * Performs client side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 17 + * Performs client side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 17 *

*/ -public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker { +public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker17.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker13.class); public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - private String expectedChallengeResponseString = null; + private String expectedChallengeResponseString; private static final String protocol = null; - private boolean allowExtensions = false; + private final boolean allowExtensions; /** - * Constructor specifying the destination web socket location and version to - * initiate + * Constructor specifying the destination web socket location and version to initiate * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version - * Version of web socket specification to use to connect to the - * server - * @param subProtocol + * Version of web socket specification to use to connect to the server + * @param subprotocol * Sub protocol request sent to the server. * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Map of custom headers to add to the client request */ - public WebSocketClientHandshaker17(URI webSocketURL, WebSocketSpecificationVersion version, String subProtocol, boolean allowExtensions) { - super(webSocketURL, version, subProtocol); + public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders) { + super(webSocketURL, version, subprotocol, customHeaders); this.allowExtensions = allowExtensions; } @@ -95,24 +95,25 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker { * Channel into which we can write our request */ @Override - public void performOpeningHandshake(Channel channel) { + public ChannelFuture handshake(Channel channel) { // Get path - URI wsURL = this.getWebSocketURL(); + URI wsURL = getWebSocketUrl(); String path = wsURL.getPath(); if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) { path = wsURL.getPath() + "?" + wsURL.getQuery(); } // Get 16 bit nonce and base 64 encode it - byte[] nonce = createRandomBytes(16); - String key = base64Encode(nonce); + byte[] nonce = WebSocketUtil.randomBytes(16); + String key = WebSocketUtil.base64(nonce); String acceptSeed = key + MAGIC_GUID; - byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); - this.expectedChallengeResponseString = base64Encode(sha1); + byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); + expectedChallengeResponseString = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { - logger.debug(String.format("HyBi17 Client Handshake key: %s. Expected response: %s.", key, this.expectedChallengeResponseString)); + logger.debug(String.format("WS Version 13 Client Handshake key: %s. Expected response: %s.", key, + expectedChallengeResponseString)); } // Format request @@ -127,9 +128,17 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker { } request.addHeader(Names.SEC_WEBSOCKET_VERSION, "13"); - channel.write(request); + if (customHeaders != null) { + for (String header : customHeaders.keySet()) { + request.addHeader(header, customHeaders.get(header)); + } + } + + ChannelFuture future = channel.write(request); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket13FrameEncoder(true)); + + return future; } /** @@ -148,13 +157,12 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker { * @param channel * Channel * @param response - * HTTP response returned from the server for the request sent by - * beginOpeningHandshake00(). + * HTTP response returned from the server for the request sent by beginOpeningHandshake00(). * @throws WebSocketHandshakeException */ @Override - public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException { - final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols"); + public void finishHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException { + final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS; if (!response.getStatus().equals(status)) { throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus()); @@ -162,22 +170,25 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker { String upgrade = response.getHeader(Names.UPGRADE); if (upgrade == null || !upgrade.equals(Values.WEBSOCKET.toLowerCase())) { - throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + response.getHeader(Names.UPGRADE)); + throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + + response.getHeader(Names.UPGRADE)); } String connection = response.getHeader(Names.CONNECTION); if (connection == null || !connection.equals(Values.UPGRADE)) { - throw new WebSocketHandshakeException("Invalid handshake response connection: " + response.getHeader(Names.CONNECTION)); + throw new WebSocketHandshakeException("Invalid handshake response connection: " + + response.getHeader(Names.CONNECTION)); } String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT); - if (accept == null || !accept.equals(this.expectedChallengeResponseString)) { - throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString)); + if (accept == null || !accept.equals(expectedChallengeResponseString)) { + throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, + expectedChallengeResponseString)); } - channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket13FrameDecoder(false, this.allowExtensions)); + channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", + new WebSocket13FrameDecoder(false, allowExtensions)); - this.setOpenningHandshakeCompleted(true); + setHandshakeComplete(); } - } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java similarity index 61% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java index e8738b5204..a199299411 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshakerFactory.java @@ -16,6 +16,7 @@ package io.netty.handler.codec.http.websocketx; import java.net.URI; +import java.util.Map; /** * Instances the appropriate handshake class to use for clients @@ -26,29 +27,28 @@ public class WebSocketClientHandshakerFactory { * Instances a new handshaker * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. * @param version - * Version of web socket specification to use to connect to the - * server - * @param subProtocol - * Sub protocol request sent to the server. Null if no - * sub-protocol support is required. + * Version of web socket specification to use to connect to the server + * @param subprotocol + * Sub protocol request sent to the server. Null if no sub-protocol support is required. * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame + * Allow extensions to be used in the reserved bits of the web socket frame + * @param customHeaders + * Custom HTTP headers to send during the handshake * @throws WebSocketHandshakeException */ - public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketSpecificationVersion version, String subProtocol, boolean allowExtensions) throws WebSocketHandshakeException { - if (version == WebSocketSpecificationVersion.V17) { - return new WebSocketClientHandshaker17(webSocketURL, version, subProtocol, allowExtensions); + public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subprotocol, + boolean allowExtensions, Map customHeaders) throws WebSocketHandshakeException { + if (version == WebSocketVersion.V13) { + return new WebSocketClientHandshaker13(webSocketURL, version, subprotocol, allowExtensions, customHeaders); } - if (version == WebSocketSpecificationVersion.V10) { - return new WebSocketClientHandshaker10(webSocketURL, version, subProtocol, allowExtensions); + if (version == WebSocketVersion.V08) { + return new WebSocketClientHandshaker08(webSocketURL, version, subprotocol, allowExtensions, customHeaders); } - if (version == WebSocketSpecificationVersion.V00) { - return new WebSocketClientHandshaker00(webSocketURL, version, subProtocol); + if (version == WebSocketVersion.V00) { + return new WebSocketClientHandshaker00(webSocketURL, version, subprotocol, customHeaders); } throw new WebSocketHandshakeException("Protocol version " + version.toString() + " not supported."); diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java similarity index 91% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java index fd48834cd7..9bad30d5c7 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrame.java @@ -23,15 +23,15 @@ import io.netty.buffer.ChannelBuffer; public abstract class WebSocketFrame { /** - * Flag to indicate if this frame is the final fragment in a message. The - * first fragment (frame) may also be the final fragment. + * Flag to indicate if this frame is the final fragment in a message. The first fragment (frame) may also be the + * final fragment. */ private boolean finalFragment = true; /** * RSV1, RSV2, RSV3 used for extensions */ - private int rsv = 0; + private int rsv; /** * Contents of this frame @@ -53,8 +53,8 @@ public abstract class WebSocketFrame { } /** - * Flag to indicate if this frame is the final fragment in a message. The - * first fragment (frame) may also be the final fragment. + * Flag to indicate if this frame is the final fragment in a message. The first fragment (frame) may also be the + * final fragment. */ public boolean isFinalFragment() { return finalFragment; diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameType.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameType.java similarity index 100% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameType.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketFrameType.java diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java similarity index 93% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java index 815d330fb1..459aa2dae6 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketHandshakeException.java @@ -18,7 +18,7 @@ package io.netty.handler.codec.http.websocketx; /** * Exception during handshaking process */ -public class WebSocketHandshakeException extends Exception { +public class WebSocketHandshakeException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java new file mode 100644 index 0000000000..5cbe843429 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java @@ -0,0 +1,139 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.LinkedHashSet; +import java.util.Set; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.base64.Base64; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.util.CharsetUtil; + +/** + * Base class for server side web socket opening and closing handshakes + */ +public abstract class WebSocketServerHandshaker { + + private final String webSocketUrl; + + private final String[] subprotocols; + + private final WebSocketVersion version; + + /** + * Constructor specifying the destination web socket location + * + * @param version + * the protocol version + * @param webSocketUrl + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols. Null if sub protocols not supported. + */ + protected WebSocketServerHandshaker( + WebSocketVersion version, String webSocketUrl, String subprotocols) { + this.version = version; + this.webSocketUrl = webSocketUrl; + if (subprotocols != null) { + String[] subprotocolArray = subprotocols.split(","); + for (int i = 0; i < subprotocolArray.length; i++) { + subprotocolArray[i] = subprotocolArray[i].trim(); + } + this.subprotocols = subprotocolArray; + } else { + this.subprotocols = new String[0]; + } + } + + /** + * Returns the URL of the web socket + */ + public String getWebSocketUrl() { + return webSocketUrl; + } + + /** + * Returns the CSV of supported sub protocols + */ + public Set getSubprotocols() { + Set ret = new LinkedHashSet(); + for (String p: this.subprotocols) { + ret.add(p); + } + return ret; + } + + /** + * Returns the version of the specification being supported + */ + public WebSocketVersion getVersion() { + return version; + } + + /** + * Performs the opening handshake + * + * @param channel + * Channel + * @param req + * HTTP Request + */ + public abstract ChannelFuture handshake(Channel channel, HttpRequest req); + + /** + * Performs the closing handshake + * + * @param channel + * Channel + * @param frame + * Closing Frame that was received + */ + public abstract ChannelFuture close(Channel channel, CloseWebSocketFrame frame); + + /** + * Selects the first matching supported sub protocol + * + * @param requestedSubprotocols + * CSV of protocols to be supported. e.g. "chat, superchat" + * @return First matching supported sub protocol. Null if not found. + */ + protected String selectSubprotocol(String requestedSubprotocols) { + if (requestedSubprotocols == null || subprotocols.length == 0) { + return null; + } + + String[] requesteSubprotocolArray = requestedSubprotocols.split(","); + for (String p: requesteSubprotocolArray) { + String requestedSubprotocol = p.trim(); + + for (String supportedSubprotocol: subprotocols) { + if (requestedSubprotocol.equals(supportedSubprotocol)) { + return requestedSubprotocol; + } + } + } + + // No match found + return null; + } +} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java similarity index 67% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java index 646037c732..4af7445fd5 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00.java @@ -15,43 +15,32 @@ */ package io.netty.handler.codec.http.websocketx; -import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION; -import static io.netty.handler.codec.http.HttpHeaders.Names.ORIGIN; -import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_KEY1; -import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_KEY2; -import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_LOCATION; -import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_ORIGIN; -import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_PROTOCOL; -import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_LOCATION; -import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_ORIGIN; -import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_PROTOCOL; -import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; -import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; - -import java.security.NoSuchAlgorithmException; +import static io.netty.handler.codec.http.HttpHeaders.Names.*; +import static io.netty.handler.codec.http.HttpHeaders.Values.*; +import static io.netty.handler.codec.http.HttpVersion.*; import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffers; import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpChunkAggregator; import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpChunkAggregator; +import io.netty.handler.codec.http.HttpHeaders.Names; +import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpHeaders.Names; -import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; /** *

- * Performs server side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 00 + * Performs server side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 00 *

*

* A very large portion of this code was taken from the Netty 3.2 HTTP example. @@ -63,49 +52,46 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { /** * Constructor specifying the destination web socket location - * + * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. - * @param subProtocols + * @param subprotocols * CSV of supported protocols */ - public WebSocketServerHandshaker00(String webSocketURL, String subProtocols) { - super(webSocketURL, subProtocols); + public WebSocketServerHandshaker00(String webSocketURL, String subprotocols) { + super(WebSocketVersion.V00, webSocketURL, subprotocols); } /** *

* Handle the web socket handshake for the web socket specification HyBi - * version 0 and lower. This standard is really a rehash of hixie-76 and hixie-75. + * "http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00">HyBi version 0 and lower. This standard + * is really a rehash of hixie-76 and + * hixie-75. *

- * + * *

* Browser request to the server: *

- * + * *
      * GET /demo HTTP/1.1
      * Upgrade: WebSocket
      * Connection: Upgrade
      * Host: example.com
      * Origin: http://example.com
+     * Sec-WebSocket-Protocol: chat, sample
      * Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
      * Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
-     *
+     * 
      * ^n:ds[4U
      * 
- * + * *

* Server response: *

- * + * *
      * HTTP/1.1 101 WebSocket Protocol Handshake
      * Upgrade: WebSocket
@@ -113,34 +99,34 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
      * Sec-WebSocket-Origin: http://example.com
      * Sec-WebSocket-Location: ws://example.com/demo
      * Sec-WebSocket-Protocol: sample
-     *
+     * 
      * 8jKS'y:G*Co,Wxa-
      * 
- * + * * @param channel * Channel * @param req * HTTP request - * @throws NoSuchAlgorithmException */ @Override - public void performOpeningHandshake(Channel channel, HttpRequest req) { + public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Channel %s web socket spec version 00 handshake", channel.getId())); + logger.debug(String.format("Channel %s WS Version 00 server handshake", channel.getId())); } - this.setVersion(WebSocketSpecificationVersion.V00); // Serve the WebSocket handshake request. - if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION)) || !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) { - return; + if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION)) + || !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) { + throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade"); } // Hixie 75 does not contain these headers while Hixie 76 does boolean isHixie76 = req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2); // Create the WebSocket handshake response. - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake")); + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, + isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake")); res.addHeader(Names.UPGRADE, WEBSOCKET); res.addHeader(CONNECTION, Values.UPGRADE); @@ -148,10 +134,10 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { if (isHixie76) { // New handshake method with a challenge: res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); - res.addHeader(SEC_WEBSOCKET_LOCATION, this.getWebSocketURL()); + res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketUrl()); String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { - res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectSubProtocol(protocol)); + res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } // Calculate the answer of the challenge. @@ -164,38 +150,42 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker { input.writeInt(a); input.writeInt(b); input.writeLong(c); - ChannelBuffer output = ChannelBuffers.wrappedBuffer(this.md5(input.array())); + ChannelBuffer output = ChannelBuffers.wrappedBuffer(WebSocketUtil.md5(input.array())); res.setContent(output); } else { // Old Hixie 75 handshake method with no challenge: res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN)); - res.addHeader(WEBSOCKET_LOCATION, this.getWebSocketURL()); + res.addHeader(WEBSOCKET_LOCATION, getWebSocketUrl()); String protocol = req.getHeader(WEBSOCKET_PROTOCOL); if (protocol != null) { - res.addHeader(WEBSOCKET_PROTOCOL, selectSubProtocol(protocol)); + res.addHeader(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } } // Upgrade the connection and send the handshake response. ChannelPipeline p = channel.getPipeline(); - p.remove(HttpChunkAggregator.class); + if (p.get(HttpChunkAggregator.class) != null) { + p.remove(HttpChunkAggregator.class); + } p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket00FrameDecoder()); - channel.write(res); + ChannelFuture future = channel.write(res); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket00FrameEncoder()); + + return future; } /** * Echo back the closing frame - * + * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override - public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) { - channel.write(frame); + public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { + return channel.write(frame); } } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker10.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java similarity index 67% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker10.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java index 30ae72e957..5fabceaf86 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker10.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08.java @@ -15,72 +15,67 @@ */ package io.netty.handler.codec.http.websocketx; -import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; -import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; - -import java.security.NoSuchAlgorithmException; +import static io.netty.handler.codec.http.HttpHeaders.Values.*; +import static io.netty.handler.codec.http.HttpVersion.*; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpChunkAggregator; import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpChunkAggregator; +import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; import io.netty.util.CharsetUtil; /** *

- * Performs server side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 10 + * Performs server side opening and closing handshakes for web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 10 *

*/ -public class WebSocketServerHandshaker10 extends WebSocketServerHandshaker { +public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker10.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker08.class); public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - private boolean allowExtensions = false; + private final boolean allowExtensions; /** * Constructor specifying the destination web socket location - * + * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. - * @param subProtocols + * @param subprotocols * CSV of supported protocols * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame + * Allow extensions to be used in the reserved bits of the web socket frame */ - public WebSocketServerHandshaker10(String webSocketURL, String subProtocols, boolean allowExtensions) { - super(webSocketURL, subProtocols); + public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) { + super(WebSocketVersion.V08, webSocketURL, subprotocols); this.allowExtensions = allowExtensions; } /** *

* Handle the web socket handshake for the web socket specification HyBi - * version 8 to 10. Version 8, 9 and 10 share the same wire protocol. + * "http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-08">HyBi version 8 to 10. Version 8, 9 and + * 10 share the same wire protocol. *

- * + * *

* Browser request to the server: *

- * + * *
      * GET /chat HTTP/1.1
      * Host: server.example.com
@@ -91,11 +86,11 @@ public class WebSocketServerHandshaker10 extends WebSocketServerHandshaker {
      * Sec-WebSocket-Protocol: chat, superchat
      * Sec-WebSocket-Version: 8
      * 
- * + * *

* Server response: *

- * + * *
      * HTTP/1.1 101 Switching Protocols
      * Upgrade: websocket
@@ -103,67 +98,69 @@ public class WebSocketServerHandshaker10 extends WebSocketServerHandshaker {
      * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
      * Sec-WebSocket-Protocol: chat
      * 
- * + * * @param channel * Channel * @param req * HTTP request - * @throws NoSuchAlgorithmException */ @Override - public void performOpeningHandshake(Channel channel, HttpRequest req) { + public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Channel %s web socket spec version 10 handshake", channel.getId())); + logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.getId())); } - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, "Switching Protocols")); - this.setVersion(WebSocketSpecificationVersion.V10); + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.getHeader(Names.SEC_WEBSOCKET_KEY); if (key == null) { - res.setStatus(HttpResponseStatus.BAD_REQUEST); - return; + throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } String acceptSeed = key + WEBSOCKET_08_ACCEPT_GUID; - byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); - String accept = base64Encode(sha1); + byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); + String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { - logger.debug(String.format("HyBi10 Server Handshake key: %s. Response: %s.", key, accept)); + logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept)); } - res.setStatus(new HttpResponseStatus(101, "Switching Protocols")); + res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.addHeader(Names.CONNECTION, Names.UPGRADE); res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept); String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { - res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.selectSubProtocol(protocol)); + res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } - channel.write(res); + ChannelFuture future = channel.write(res); // Upgrade the connection and send the handshake response. ChannelPipeline p = channel.getPipeline(); - p.remove(HttpChunkAggregator.class); - p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket08FrameDecoder(true, this.allowExtensions)); + if (p.get(HttpChunkAggregator.class) != null) { + p.remove(HttpChunkAggregator.class); + } + + p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket08FrameDecoder(true, allowExtensions)); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket08FrameEncoder(false)); + return future; } /** * Echo back the closing frame and close the connection - * + * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override - public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) { + public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { ChannelFuture f = channel.write(frame); f.addListener(ChannelFutureListener.CLOSE); + return f; } } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker17.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java similarity index 66% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker17.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java index 45383cbe09..f8debb39c9 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker17.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13.java @@ -18,8 +18,6 @@ package io.netty.handler.codec.http.websocketx; import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; -import java.security.NoSuchAlgorithmException; - import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; @@ -38,49 +36,47 @@ import io.netty.util.CharsetUtil; /** *

- * Performs server side opening and closing handshakes for web socket - * specification version draft-ietf-hybi-thewebsocketprotocol- 17 + * Performs server side opening and closing handshakes for RFC 6455 + * (originally web socket specification version draft-ietf-hybi-thewebsocketprotocol- + * 17). *

*/ -public class WebSocketServerHandshaker17 extends WebSocketServerHandshaker { +public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker17.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandshaker13.class); - public static final String WEBSOCKET_17_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - private boolean allowExtensions = false; + private final boolean allowExtensions; /** * Constructor specifying the destination web socket location - * + * * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be * sent to this URL. - * @param subProtocols + * @param subprotocols * CSV of supported protocols * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame + * Allow extensions to be used in the reserved bits of the web socket frame */ - public WebSocketServerHandshaker17(String webSocketURL, String subProtocols, boolean allowExtensions) { - super(webSocketURL, subProtocols); + public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions) { + super(WebSocketVersion.V13, webSocketURL, subprotocols); this.allowExtensions = allowExtensions; } /** *

* Handle the web socket handshake for the web socket specification HyBi - * versions 13-17. Versions 13-17 share the same wire protocol. + * "http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17">HyBi versions 13-17. Versions 13-17 + * share the same wire protocol. *

- * + * *

* Browser request to the server: *

- * + * *
      * GET /chat HTTP/1.1
      * Host: server.example.com
@@ -91,11 +87,11 @@ public class WebSocketServerHandshaker17 extends WebSocketServerHandshaker {
      * Sec-WebSocket-Protocol: chat, superchat
      * Sec-WebSocket-Version: 13
      * 
- * + * *

* Server response: *

- * + * *
      * HTTP/1.1 101 Switching Protocols
      * Upgrade: websocket
@@ -103,67 +99,69 @@ public class WebSocketServerHandshaker17 extends WebSocketServerHandshaker {
      * Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
      * Sec-WebSocket-Protocol: chat
      * 
- * + * * @param channel * Channel * @param req * HTTP request - * @throws NoSuchAlgorithmException */ @Override - public void performOpeningHandshake(Channel channel, HttpRequest req) { + public ChannelFuture handshake(Channel channel, HttpRequest req) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Channel %s web socket spec version 17 handshake", channel.getId())); + logger.debug(String.format("Channel %s WS Version 13 server handshake", channel.getId())); } - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, "Switching Protocols")); - this.setVersion(WebSocketSpecificationVersion.V17); + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS); String key = req.getHeader(Names.SEC_WEBSOCKET_KEY); if (key == null) { - res.setStatus(HttpResponseStatus.BAD_REQUEST); - return; + throw new WebSocketHandshakeException("not a WebSocket request: missing key"); } - String acceptSeed = key + WEBSOCKET_17_ACCEPT_GUID; - byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); - String accept = base64Encode(sha1); + String acceptSeed = key + WEBSOCKET_13_ACCEPT_GUID; + byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII)); + String accept = WebSocketUtil.base64(sha1); if (logger.isDebugEnabled()) { - logger.debug(String.format("HyBi17 Server Handshake key: %s. Response: %s.", key, accept)); + logger.debug(String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept)); } - res.setStatus(new HttpResponseStatus(101, "Switching Protocols")); + res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS); res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); res.addHeader(Names.CONNECTION, Names.UPGRADE); res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept); String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); if (protocol != null) { - res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.selectSubProtocol(protocol)); + res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol)); } - channel.write(res); + ChannelFuture future = channel.write(res); // Upgrade the connection and send the handshake response. ChannelPipeline p = channel.getPipeline(); - p.remove(HttpChunkAggregator.class); - p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, this.allowExtensions)); + if (p.get(HttpChunkAggregator.class) != null) { + p.remove(HttpChunkAggregator.class); + } + + p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, allowExtensions)); p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket13FrameEncoder(false)); + return future; } /** * Echo back the closing frame and close the connection - * + * * @param channel * Channel * @param frame * Web Socket frame that was received */ @Override - public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) { + public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) { ChannelFuture f = channel.write(frame); f.addListener(ChannelFutureListener.CLOSE); + return f; } } diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java new file mode 100644 index 0000000000..4428bc5ea0 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java @@ -0,0 +1,94 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.HttpHeaders.Names; + +/** + * Instances the appropriate handshake class to use for servers + */ +public class WebSocketServerHandshakerFactory { + + private final String webSocketURL; + + private final String subprotocols; + + private final boolean allowExtensions; + + /** + * Constructor specifying the destination web socket location + * + * @param webSocketURL + * URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be + * sent to this URL. + * @param subprotocols + * CSV of supported protocols. Null if sub protocols not supported. + * @param allowExtensions + * Allow extensions to be used in the reserved bits of the web socket frame + */ + public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions) { + this.webSocketURL = webSocketURL; + this.subprotocols = subprotocols; + this.allowExtensions = allowExtensions; + } + + /** + * Instances a new handshaker + * + * @return A new WebSocketServerHandshaker for the requested web socket version. Null if web socket version is not + * supported. + */ + public WebSocketServerHandshaker newHandshaker(HttpRequest req) { + + String version = req.getHeader(Names.SEC_WEBSOCKET_VERSION); + if (version != null) { + if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) { + // Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification). + return new WebSocketServerHandshaker13(webSocketURL, subprotocols, allowExtensions); + } else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) { + // Version 8 of the wire protocol - version 10 of the draft hybi specification. + return new WebSocketServerHandshaker08(webSocketURL, subprotocols, allowExtensions); + } else { + return null; + } + } else { + // Assume version 00 where version header was not specified + return new WebSocketServerHandshaker00(webSocketURL, subprotocols); + } + } + + /** + * Return that we need cannot not support the web socket version + * + * @param channel + * Channel + */ + public void sendUnsupportedWebSocketVersionResponse(Channel channel) { + HttpResponse res = new DefaultHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.SWITCHING_PROTOCOLS); + res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED); + res.setHeader(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue()); + channel.write(res); + } + +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketUtil.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketUtil.java new file mode 100644 index 0000000000..ffe7efcfbd --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketUtil.java @@ -0,0 +1,109 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.handler.codec.base64.Base64; +import io.netty.util.CharsetUtil; + +/** + * TODO Document me. + */ +final class WebSocketUtil { + + /** + * Performs an MD5 hash + * + * @param bytes + * Data to hash + * @return Hashed data + */ + static byte[] md5(byte[] bytes) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + return md.digest(bytes); + } catch (NoSuchAlgorithmException e) { + throw new InternalError("MD5 not supported on this platform"); + } + } + + /** + * Performs an SHA-1 hash + * + * @param bytes + * Data to hash + * @return Hashed data + */ + static byte[] sha1(byte[] bytes) { + try { + MessageDigest md = MessageDigest.getInstance("SHA1"); + return md.digest(bytes); + } catch (NoSuchAlgorithmException e) { + throw new InternalError("SHA-1 not supported on this platform"); + } + } + + /** + * Base 64 encoding + * + * @param bytes + * Bytes to encode + * @return encoded string + */ + static String base64(byte[] bytes) { + ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes); + return Base64.encode(hashed).toString(CharsetUtil.UTF_8); + } + + /** + * Creates some random bytes + * + * @param size + * Number of random bytes to create + * @return random bytes + */ + static byte[] randomBytes(int size) { + byte[] bytes = new byte[size]; + + for (int i = 0; i < size; i++) { + bytes[i] = (byte) randomNumber(0, 255); + } + + return bytes; + } + + /** + * Generates a random number + * + * @param min + * Minimum value + * @param max + * Maximum value + * @return Random number + */ + static int randomNumber(int min, int max) { + return (int) (Math.random() * max + min); + } + + + private WebSocketUtil() { + // Unused + } +} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketSpecificationVersion.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketVersion.java similarity index 56% rename from src/main/java/io/netty/handler/codec/http/websocketx/WebSocketSpecificationVersion.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketVersion.java index 65f2d03538..b538e7e805 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketSpecificationVersion.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketVersion.java @@ -20,32 +20,43 @@ package io.netty.handler.codec.http.websocketx; * Versions of the web socket specification. *

*

- * A specification is tied to one wire protocol version but a protocol version - * may have use by more than 1 version of the specification. + * A specification is tied to one wire protocol version but a protocol version may have use by more than 1 version of + * the specification. *

*/ -public enum WebSocketSpecificationVersion { +public enum WebSocketVersion { UNKNOWN, /** - * draft-ietf-hybi-thewebsocketprotocol- 00. */ V00, /** - * draft-ietf-hybi-thewebsocketprotocol- 10 */ - V10, - + V08, + /** - * draft-ietf-hybi-thewebsocketprotocol- 17 + * RFC 6455. This was originally draft-ietf-hybi-thewebsocketprotocol- + * 17 */ - V17 - + V13; + + /** + * @return Value for HTTP Header 'Sec-WebSocket-Version' + */ + public String toHttpHeaderValue() { + if (this == V00) { + return "0"; + } else if (this == V08) { + return "8"; + } else if (this == V13) { + return "13"; + } + throw new IllegalStateException("Unknown web socket version: " + this); + } } diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/package-info.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/package-info.java similarity index 81% rename from src/main/java/io/netty/handler/codec/http/websocketx/package-info.java rename to codec-http/src/main/java/io/netty/handler/codec/http/websocketx/package-info.java index 5790d0061f..c0f214d812 100644 --- a/src/main/java/io/netty/handler/codec/http/websocketx/package-info.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/package-info.java @@ -23,15 +23,10 @@ * *

*

- * In the future, as the specification develops, more versions will be supported. - * This contrasts the io.netty.handler.codec.http.websocket package which only - * supports draft-ietf-hybi-thewebsocketprotocol-00. - *

- *

* For the detailed instruction on adding add Web Socket support to your HTTP * server, take a look into the WebSocketServerX example located in the * {@code io.netty.example.http.websocket} package. diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java similarity index 99% rename from src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java index 7e0e7e9159..77ae287deb 100644 --- a/src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java +++ b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspHeaders.java @@ -27,7 +27,7 @@ public final class RtspHeaders { /** * Standard RTSP header names. - */ + */ public static final class Names { /** * {@code "Accept"} @@ -212,7 +212,7 @@ public final class RtspHeaders { /** * Standard RTSP header values. - */ + */ public static final class Values { /** * {@code "append"} diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspMessageDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMessageDecoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspMessageDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMessageDecoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspMessageEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMessageEncoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspMessageEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMessageEncoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspMethods.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMethods.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspMethods.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspMethods.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestDecoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspRequestEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestEncoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspRequestEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspRequestEncoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseDecoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspResponseEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseEncoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspResponseEncoder.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseEncoder.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspResponseStatuses.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseStatuses.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspResponseStatuses.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspResponseStatuses.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/RtspVersions.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspVersions.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/RtspVersions.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/RtspVersions.java diff --git a/src/main/java/io/netty/handler/codec/rtsp/package-info.java b/codec-http/src/main/java/io/netty/handler/codec/rtsp/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/rtsp/package-info.java rename to codec-http/src/main/java/io/netty/handler/codec/rtsp/package-info.java diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyDataFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyDataFrame.java new file mode 100644 index 0000000000..8d2bfa2070 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyDataFrame.java @@ -0,0 +1,116 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyDataFrame} implementation. + */ +public class DefaultSpdyDataFrame implements SpdyDataFrame { + + private int streamID; + private boolean last; + private boolean compressed; + private ChannelBuffer data = ChannelBuffers.EMPTY_BUFFER; + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + */ + public DefaultSpdyDataFrame(int streamID) { + setStreamID(streamID); + } + + public int getStreamID() { + return streamID; + } + + public void setStreamID(int streamID) { + if (streamID <= 0) { + throw new IllegalArgumentException( + "Stream-ID must be positive: " + streamID); + } + this.streamID = streamID; + } + + public boolean isLast() { + return last; + } + + public void setLast(boolean last) { + this.last = last; + } + + public boolean isCompressed() { + return compressed; + } + + public void setCompressed(boolean compressed) { + this.compressed = compressed; + } + + public ChannelBuffer getData() { + return data; + } + + public void setData(ChannelBuffer data) { + if (data == null) { + data = ChannelBuffers.EMPTY_BUFFER; + } + if (data.readableBytes() > SpdyCodecUtil.SPDY_MAX_LENGTH) { + throw new IllegalArgumentException("data payload cannot exceed " + + SpdyCodecUtil.SPDY_MAX_LENGTH + " bytes"); + } + this.data = data; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append("(last: "); + buf.append(isLast()); + buf.append("; compressed: "); + buf.append(isCompressed()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + buf.append("--> Stream-ID = "); + buf.append(streamID); + buf.append(StringUtil.NEWLINE); + buf.append("--> Size = "); + buf.append(data.readableBytes()); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyGoAwayFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyGoAwayFrame.java new file mode 100644 index 0000000000..386eb7f750 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyGoAwayFrame.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyGoAwayFrame} implementation. + */ +public class DefaultSpdyGoAwayFrame implements SpdyGoAwayFrame { + + private int lastGoodStreamID; + + /** + * Creates a new instance. + * + * @param lastGoodStreamID the Last-good-stream-ID of this frame + */ + public DefaultSpdyGoAwayFrame(int lastGoodStreamID) { + setLastGoodStreamID(lastGoodStreamID); + } + + public int getLastGoodStreamID() { + return lastGoodStreamID; + } + + public void setLastGoodStreamID(int lastGoodStreamID) { + if (lastGoodStreamID < 0) { + throw new IllegalArgumentException("Last-good-stream-ID" + + " cannot be negative: " + lastGoodStreamID); + } + this.lastGoodStreamID = lastGoodStreamID; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append(StringUtil.NEWLINE); + buf.append("--> Last-good-stream-ID = "); + buf.append(lastGoodStreamID); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeaderBlock.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeaderBlock.java new file mode 100644 index 0000000000..4049ef94a6 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeaderBlock.java @@ -0,0 +1,110 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyHeaderBlock} implementation. + */ +public class DefaultSpdyHeaderBlock implements SpdyHeaderBlock { + + private boolean invalid; + private final SpdyHeaders headers = new SpdyHeaders(); + + /** + * Creates a new instance. + */ + protected DefaultSpdyHeaderBlock() { + } + + public boolean isInvalid() { + return invalid; + } + + public void setInvalid() { + this.invalid = true; + } + + public void addHeader(final String name, final Object value) { + headers.addHeader(name, value); + } + + public void setHeader(final String name, final Object value) { + headers.setHeader(name, value); + } + + public void setHeader(final String name, final Iterable values) { + headers.setHeader(name, values); + } + + public void removeHeader(final String name) { + headers.removeHeader(name); + } + + public void clearHeaders() { + headers.clearHeaders(); + } + + public String getHeader(final String name) { + return headers.getHeader(name); + } + + public List getHeaders(final String name) { + return headers.getHeaders(name); + } + + public List> getHeaders() { + return headers.getHeaders(); + } + + public boolean containsHeader(final String name) { + return headers.containsHeader(name); + } + + public Set getHeaderNames() { + return headers.getHeaderNames(); + } + + protected void appendHeaders(StringBuilder buf) { + for (Map.Entry e: getHeaders()) { + buf.append(" "); + buf.append(e.getKey()); + buf.append(": "); + buf.append(e.getValue()); + buf.append(StringUtil.NEWLINE); + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeadersFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeadersFrame.java new file mode 100644 index 0000000000..f0e8bc9030 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyHeadersFrame.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyHeadersFrame} implementation. + */ +public class DefaultSpdyHeadersFrame extends DefaultSpdyHeaderBlock + implements SpdyHeadersFrame { + + private int streamID; + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + */ + public DefaultSpdyHeadersFrame(int streamID) { + super(); + setStreamID(streamID); + } + + public int getStreamID() { + return streamID; + } + + public void setStreamID(int streamID) { + if (streamID <= 0) { + throw new IllegalArgumentException( + "Stream-ID must be positive: " + streamID); + } + this.streamID = streamID; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append(StringUtil.NEWLINE); + buf.append("--> Stream-ID = "); + buf.append(streamID); + buf.append(StringUtil.NEWLINE); + buf.append("--> Headers:"); + buf.append(StringUtil.NEWLINE); + appendHeaders(buf); + + // Remove the last newline. + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyNoOpFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyNoOpFrame.java new file mode 100644 index 0000000000..a976baf304 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyNoOpFrame.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * The default {@link SpdyNoOpFrame} implementation. + */ +public class DefaultSpdyNoOpFrame implements SpdyNoOpFrame { + + /** + * Creates a new instance. + */ + public DefaultSpdyNoOpFrame() { + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyPingFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyPingFrame.java new file mode 100644 index 0000000000..ae0119dd68 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyPingFrame.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyPingFrame} implementation. + */ +public class DefaultSpdyPingFrame implements SpdyPingFrame { + + private int ID; + + /** + * Creates a new instance. + * + * @param ID the unique ID of this frame + */ + public DefaultSpdyPingFrame(int ID) { + setID(ID); + } + + public int getID() { + return ID; + } + + public void setID(int ID) { + this.ID = ID; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append(StringUtil.NEWLINE); + buf.append("--> ID = "); + buf.append(ID); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyRstStreamFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyRstStreamFrame.java new file mode 100644 index 0000000000..3273eed153 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdyRstStreamFrame.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdyRstStreamFrame} implementation. + */ +public class DefaultSpdyRstStreamFrame implements SpdyRstStreamFrame { + + private int streamID; + private SpdyStreamStatus status; + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + * @param statusCode the Status code of this frame + */ + public DefaultSpdyRstStreamFrame(int streamID, int statusCode) { + this(streamID, SpdyStreamStatus.valueOf(statusCode)); + } + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + * @param status the status of this frame + */ + public DefaultSpdyRstStreamFrame(int streamID, SpdyStreamStatus status) { + setStreamID(streamID); + setStatus(status); + } + + public int getStreamID() { + return streamID; + } + + public void setStreamID(int streamID) { + if (streamID <= 0) { + throw new IllegalArgumentException( + "Stream-ID must be positive: " + streamID); + } + this.streamID = streamID; + } + + public SpdyStreamStatus getStatus() { + return status; + } + + public void setStatus(SpdyStreamStatus status) { + this.status = status; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append(StringUtil.NEWLINE); + buf.append("--> Stream-ID = "); + buf.append(streamID); + buf.append(StringUtil.NEWLINE); + buf.append("--> Status: "); + buf.append(status.toString()); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySettingsFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySettingsFrame.java new file mode 100644 index 0000000000..1cb20818e4 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySettingsFrame.java @@ -0,0 +1,203 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdySettingsFrame} implementation. + */ +public class DefaultSpdySettingsFrame implements SpdySettingsFrame { + + private boolean clear; + private final Map settingsMap = new TreeMap(); + + /** + * Creates a new instance. + */ + public DefaultSpdySettingsFrame() { + } + + public Set getIDs() { + return settingsMap.keySet(); + } + + public boolean isSet(int ID) { + Integer key = new Integer(ID); + return settingsMap.containsKey(key); + } + + public int getValue(int ID) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + return settingsMap.get(key).getValue(); + } else { + return -1; + } + } + + public void setValue(int ID, int value) { + setValue(ID, value, false, false); + } + + public void setValue(int ID, int value, boolean persistValue, boolean persisted) { + if (ID <= 0 || ID > SpdyCodecUtil.SPDY_SETTINGS_MAX_ID) { + throw new IllegalArgumentException("Setting ID is not valid: " + ID); + } + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + Setting setting = settingsMap.get(key); + setting.setValue(value); + setting.setPersist(persistValue); + setting.setPersisted(persisted); + } else { + settingsMap.put(key, new Setting(value, persistValue, persisted)); + } + } + + public void removeValue(int ID) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + settingsMap.remove(key); + } + } + + public boolean persistValue(int ID) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + return settingsMap.get(key).getPersist(); + } else { + return false; + } + } + + public void setPersistValue(int ID, boolean persistValue) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + settingsMap.get(key).setPersist(persistValue); + } + } + + public boolean isPersisted(int ID) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + return settingsMap.get(key).getPersisted(); + } else { + return false; + } + } + + public void setPersisted(int ID, boolean persisted) { + Integer key = new Integer(ID); + if (settingsMap.containsKey(key)) { + settingsMap.get(key).setPersisted(persisted); + } + } + + public boolean clearPreviouslyPersistedSettings() { + return clear; + } + + public void setClearPreviouslyPersistedSettings(boolean clear) { + this.clear = clear; + } + + private Set> getSettings() { + return settingsMap.entrySet(); + } + + private void appendSettings(StringBuilder buf) { + for (Map.Entry e: getSettings()) { + Setting setting = e.getValue(); + buf.append("--> "); + buf.append(e.getKey().toString()); + buf.append(":"); + buf.append(setting.getValue()); + buf.append(" (persist value: "); + buf.append(setting.getPersist()); + buf.append("; persisted: "); + buf.append(setting.getPersisted()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append(StringUtil.NEWLINE); + appendSettings(buf); + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } + + private static final class Setting { + + private int value; + private boolean persist; + private boolean persisted; + + public Setting(int value, boolean persist, boolean persisted) { + this.value = value; + this.persist = persist; + this.persisted = persisted; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public boolean getPersist() { + return persist; + } + + public void setPersist(boolean persist) { + this.persist = persist; + } + + public boolean getPersisted() { + return persisted; + } + + public void setPersisted(boolean persisted) { + this.persisted = persisted; + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynReplyFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynReplyFrame.java new file mode 100644 index 0000000000..dba75a7f37 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynReplyFrame.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdySynReplyFrame} implementation. + */ +public class DefaultSpdySynReplyFrame extends DefaultSpdyHeaderBlock + implements SpdySynReplyFrame { + + private int streamID; + private boolean last; + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + */ + public DefaultSpdySynReplyFrame(int streamID) { + super(); + setStreamID(streamID); + } + + public int getStreamID() { + return streamID; + } + + public void setStreamID(int streamID) { + if (streamID <= 0) { + throw new IllegalArgumentException( + "Stream-ID must be positive: " + streamID); + } + this.streamID = streamID; + } + + public boolean isLast() { + return last; + } + + public void setLast(boolean last) { + this.last = last; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append("(last: "); + buf.append(isLast()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + buf.append("--> Stream-ID = "); + buf.append(streamID); + buf.append(StringUtil.NEWLINE); + buf.append("--> Headers:"); + buf.append(StringUtil.NEWLINE); + appendHeaders(buf); + + // Remove the last newline. + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynStreamFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynStreamFrame.java new file mode 100644 index 0000000000..95d1d9fe1a --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/DefaultSpdySynStreamFrame.java @@ -0,0 +1,144 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.util.internal.StringUtil; + +/** + * The default {@link SpdySynStreamFrame} implementation. + */ +public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock + implements SpdySynStreamFrame { + + private int streamID; + private int associatedToStreamID; + private byte priority; + private boolean last; + private boolean unidirectional; + + /** + * Creates a new instance. + * + * @param streamID the Stream-ID of this frame + * @param associatedToStreamID the Associated-To-Stream-ID of this frame + * @param priority the priority of the stream + */ + public DefaultSpdySynStreamFrame( + int streamID, int associatedToStreamID, byte priority) { + super(); + setStreamID(streamID); + setAssociatedToStreamID(associatedToStreamID); + setPriority(priority); + } + + public int getStreamID() { + return streamID; + } + + public void setStreamID(int streamID) { + if (streamID <= 0) { + throw new IllegalArgumentException( + "Stream-ID must be positive: " + streamID); + } + this.streamID = streamID; + } + + public int getAssociatedToStreamID() { + return associatedToStreamID; + } + + public void setAssociatedToStreamID(int associatedToStreamID) { + if (associatedToStreamID < 0) { + throw new IllegalArgumentException( + "Associated-To-Stream-ID cannot be negative: " + + associatedToStreamID); + } + this.associatedToStreamID = associatedToStreamID; + } + + public byte getPriority() { + return priority; + } + + public void setPriority(byte priority) { + if (priority < 0 || priority > 3) { + throw new IllegalArgumentException( + "Priortiy must be between 0 and 3 inclusive: " + priority); + } + this.priority = priority; + } + + public boolean isLast() { + return last; + } + + public void setLast(boolean last) { + this.last = last; + } + + public boolean isUnidirectional() { + return unidirectional; + } + + public void setUnidirectional(boolean unidirectional) { + this.unidirectional = unidirectional; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append(getClass().getSimpleName()); + buf.append("(last: "); + buf.append(isLast()); + buf.append("; unidirectional: "); + buf.append(isUnidirectional()); + buf.append(')'); + buf.append(StringUtil.NEWLINE); + buf.append("--> Stream-ID = "); + buf.append(streamID); + buf.append(StringUtil.NEWLINE); + if (associatedToStreamID != 0) { + buf.append("--> Associated-To-Stream-ID = "); + buf.append(associatedToStreamID); + buf.append(StringUtil.NEWLINE); + } + buf.append("--> Priority = "); + buf.append(priority); + buf.append(StringUtil.NEWLINE); + buf.append("--> Headers:"); + buf.append(StringUtil.NEWLINE); + appendHeaders(buf); + + // Remove the last newline. + buf.setLength(buf.length() - StringUtil.NEWLINE.length()); + return buf.toString(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyCodecUtil.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyCodecUtil.java new file mode 100644 index 0000000000..599cf9fb73 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyCodecUtil.java @@ -0,0 +1,191 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.buffer.ChannelBuffer; + +final class SpdyCodecUtil { + + static final int SPDY_VERSION = 2; + + static final int SPDY_HEADER_TYPE_OFFSET = 2; + static final int SPDY_HEADER_FLAGS_OFFSET = 4; + static final int SPDY_HEADER_LENGTH_OFFSET = 5; + static final int SPDY_HEADER_SIZE = 8; + + static final int SPDY_MAX_LENGTH = 0xFFFFFF; // Length is a 24-bit field + + static final byte SPDY_DATA_FLAG_FIN = 0x01; + static final byte SPDY_DATA_FLAG_COMPRESS = 0x02; + + static final int SPDY_SYN_STREAM_FRAME = 1; + static final int SPDY_SYN_REPLY_FRAME = 2; + static final int SPDY_RST_STREAM_FRAME = 3; + static final int SPDY_SETTINGS_FRAME = 4; + static final int SPDY_NOOP_FRAME = 5; + static final int SPDY_PING_FRAME = 6; + static final int SPDY_GOAWAY_FRAME = 7; + static final int SPDY_HEADERS_FRAME = 8; + static final int SPDY_WINDOW_UPDATE_FRAME = 9; + + static final byte SPDY_FLAG_FIN = 0x01; + static final byte SPDY_FLAG_UNIDIRECTIONAL = 0x02; + + static final byte SPDY_SETTINGS_CLEAR = 0x01; + static final byte SPDY_SETTINGS_PERSIST_VALUE = 0x01; + static final byte SPDY_SETTINGS_PERSISTED = 0x02; + + static final int SPDY_SETTINGS_MAX_ID = 0xFFFFFF; // ID is a 24-bit field + + static final int SPDY_MAX_NV_LENGTH = 0xFFFF; // Length is a 16-bit field + + // Zlib Dictionary + private static final String SPDY_DICT_S = + "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" + + "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" + + "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" + + "-agent10010120020120220320420520630030130230330430530630740040140240340440" + + "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" + + "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" + + "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" + + "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" + + "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" + + "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" + + "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" + + "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" + + ".1statusversionurl "; + static final byte[] SPDY_DICT; + static { + byte[] SPDY_DICT_ = null; + + try { + SPDY_DICT_ = SPDY_DICT_S.getBytes("US-ASCII"); + // dictionary is null terminated + SPDY_DICT_[SPDY_DICT_.length - 1] = (byte) 0; + } catch (Exception e) { + SPDY_DICT_ = new byte[1]; + } + + SPDY_DICT = SPDY_DICT_; + } + + + private SpdyCodecUtil() { + } + + + /** + * Reads a big-endian unsigned short integer from the buffer. + */ + static int getUnsignedShort(ChannelBuffer buf, int offset) { + return (int) ((buf.getByte(offset) & 0xFF) << 8 | + (buf.getByte(offset + 1) & 0xFF)); + } + + /** + * Reads a big-endian unsigned medium integer from the buffer. + */ + static int getUnsignedMedium(ChannelBuffer buf, int offset) { + return (int) ((buf.getByte(offset) & 0xFF) << 16 | + (buf.getByte(offset + 1) & 0xFF) << 8 | + (buf.getByte(offset + 2) & 0xFF)); + } + + /** + * Reads a big-endian (31-bit) integer from the buffer. + */ + static int getUnsignedInt(ChannelBuffer buf, int offset) { + return (int) ((buf.getByte(offset) & 0x7F) << 24 | + (buf.getByte(offset + 1) & 0xFF) << 16 | + (buf.getByte(offset + 2) & 0xFF) << 8 | + (buf.getByte(offset + 3) & 0xFF)); + } + + /** + * Reads a big-endian signed integer from the buffer. + */ + static int getSignedInt(ChannelBuffer buf, int offset) { + return (int) ((buf.getByte(offset) & 0xFF) << 24 | + (buf.getByte(offset + 1) & 0xFF) << 16 | + (buf.getByte(offset + 2) & 0xFF) << 8 | + (buf.getByte(offset + 3) & 0xFF)); + } + + /** + * Validate a SPDY header name. + */ + static void validateHeaderName(String name) { + if (name == null) { + throw new NullPointerException("name"); + } + if (name.length() == 0) { + throw new IllegalArgumentException( + "name cannot be length zero"); + } + // Since name may only contain ascii characters, for valid names + // name.length() returns the number of bytes when UTF-8 encoded. + if (name.length() > SPDY_MAX_NV_LENGTH) { + throw new IllegalArgumentException( + "name exceeds allowable length: " + name); + } + for (int i = 0; i < name.length(); i ++) { + char c = name.charAt(i); + if (c == 0) { + throw new IllegalArgumentException( + "name contains null character: " + name); + } + if (c > 127) { + throw new IllegalArgumentException( + "name contains non-ascii character: " + name); + } + } + } + + /** + * Validate a SPDY header value. Does not validate max length. + */ + static void validateHeaderValue(String value) { + if (value == null) { + throw new NullPointerException("value"); + } + if (value.length() == 0) { + throw new IllegalArgumentException( + "value cannot be length zero"); + } + for (int i = 0; i < value.length(); i ++) { + char c = value.charAt(i); + if (c == 0) { + throw new IllegalArgumentException( + "value contains null character: " + value); + } + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyDataFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyDataFrame.java new file mode 100644 index 0000000000..9754154786 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyDataFrame.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; + +/** + * A SPDY Protocol Data Frame + */ +public interface SpdyDataFrame { + + /** + * Returns the Stream-ID of this frame. + */ + int getStreamID(); + + /** + * Sets the Stream-ID of this frame. The Stream-ID must be positive. + */ + void setStreamID(int streamID); + + /** + * Returns {@code true} if this frame is the last frame to be transmitted + * on the stream. + */ + boolean isLast(); + + /** + * Sets if this frame is the last frame to be transmitted on the stream. + */ + void setLast(boolean last); + + /** + * Returns {@code true} if the data in this frame has been compressed. + */ + boolean isCompressed(); + + /** + * Sets if the data in this frame has been compressed. + */ + void setCompressed(boolean compressed); + + /** + * Returns the data payload of this frame. If there is no data payload + * {@link ChannelBuffers#EMPTY_BUFFER} is returned. + */ + ChannelBuffer getData(); + + /** + * Sets the data payload of this frame. If {@code null} is specified, + * the data payload will be set to {@link ChannelBuffers#EMPTY_BUFFER}. + * The data payload cannot exceed 16777215 bytes. + */ + void setData(ChannelBuffer data); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java new file mode 100644 index 0000000000..fd424f5ef5 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameCodec.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.channel.ChannelDownstreamHandler; +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelUpstreamHandler; + +/** + * A combination of {@link SpdyFrameDecoder} and {@link SpdyFrameEncoder}. + * @apiviz.has io.netty.handler.codec.spdy.SpdyFrameDecoder + * @apiviz.has io.netty.handler.codec.spdy.SpdyFrameEncoder + */ +public class SpdyFrameCodec implements ChannelUpstreamHandler, + ChannelDownstreamHandler { + + private final SpdyFrameDecoder decoder = new SpdyFrameDecoder(); + private final SpdyFrameEncoder encoder = new SpdyFrameEncoder(); + + public SpdyFrameCodec() { + } + + public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) + throws Exception { + decoder.handleUpstream(ctx, e); + } + + public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) + throws Exception { + encoder.handleDownstream(ctx, e); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java new file mode 100644 index 0000000000..001d507c8f --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameDecoder.java @@ -0,0 +1,337 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import io.netty.buffer.ChannelBuffer; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.compression.ZlibDecoder; +import io.netty.handler.codec.embedder.DecoderEmbedder; +import io.netty.handler.codec.frame.FrameDecoder; + +import static io.netty.handler.codec.spdy.SpdyCodecUtil.*; + +/** + * Decodes {@link ChannelBuffer}s into SPDY Data and Control Frames. + */ +public class SpdyFrameDecoder extends FrameDecoder { + + private final DecoderEmbedder headerBlockDecompressor = + new DecoderEmbedder(new ZlibDecoder(SPDY_DICT)); + + public SpdyFrameDecoder() { + super(); + } + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) + throws Exception { + + // Must read common header to determine frame length + if (buffer.readableBytes() < SPDY_HEADER_SIZE) { + return null; + } + + // Get frame length from common header + int frameOffset = buffer.readerIndex(); + int lengthOffset = frameOffset + SPDY_HEADER_LENGTH_OFFSET; + int dataLength = getUnsignedMedium(buffer, lengthOffset); + int frameLength = SPDY_HEADER_SIZE + dataLength; + + // Wait until entire frame is readable + if (buffer.readableBytes() < frameLength) { + return null; + } + + // Read common header fields + boolean control = (buffer.getByte(frameOffset) & 0x80) != 0; + int flagsOffset = frameOffset + SPDY_HEADER_FLAGS_OFFSET; + byte flags = buffer.getByte(flagsOffset); + + if (control) { + // Decode control frame common header + int version = getUnsignedShort(buffer, frameOffset) & 0x7FFF; + + // Spdy versioning spec is broken + if (version != SPDY_VERSION) { + buffer.skipBytes(frameLength); + throw new SpdyProtocolException( + "Unsupported version: " + version); + } + + int typeOffset = frameOffset + SPDY_HEADER_TYPE_OFFSET; + int type = getUnsignedShort(buffer, typeOffset); + buffer.skipBytes(SPDY_HEADER_SIZE); + + return decodeControlFrame(type, flags, buffer.readBytes(dataLength)); + } else { + // Decode data frame common header + int streamID = getUnsignedInt(buffer, frameOffset); + buffer.skipBytes(SPDY_HEADER_SIZE); + + SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamID); + spdyDataFrame.setLast((flags & SPDY_DATA_FLAG_FIN) != 0); + spdyDataFrame.setCompressed((flags & SPDY_DATA_FLAG_COMPRESS) != 0); + spdyDataFrame.setData(buffer.readBytes(dataLength)); + + return spdyDataFrame; + } + } + + private Object decodeControlFrame(int type, byte flags, ChannelBuffer data) + throws Exception { + int streamID; + boolean last; + + switch (type) { + case SPDY_SYN_STREAM_FRAME: + if (data.readableBytes() < 12) { + throw new SpdyProtocolException( + "Received invalid SYN_STREAM control frame"); + } + streamID = getUnsignedInt(data, data.readerIndex()); + int associatedToStreamID = getUnsignedInt(data, data.readerIndex() + 4); + byte priority = (byte) (data.getByte(data.readerIndex() + 8) >> 6 & 0x03); + data.skipBytes(10); + + SpdySynStreamFrame spdySynStreamFrame = + new DefaultSpdySynStreamFrame(streamID, associatedToStreamID, priority); + + last = (flags & SPDY_FLAG_FIN) != 0; + boolean unid = (flags & SPDY_FLAG_UNIDIRECTIONAL) != 0; + spdySynStreamFrame.setLast(last); + spdySynStreamFrame.setUnidirectional(unid); + + decodeHeaderBlock(spdySynStreamFrame, decompress(data)); + + return spdySynStreamFrame; + + case SPDY_SYN_REPLY_FRAME: + if (data.readableBytes() < 8) { + throw new SpdyProtocolException( + "Received invalid SYN_REPLY control frame"); + } + streamID = getUnsignedInt(data, data.readerIndex()); + data.skipBytes(6); + + SpdySynReplyFrame spdySynReplyFrame = + new DefaultSpdySynReplyFrame(streamID); + + last = (flags & SPDY_FLAG_FIN) != 0; + spdySynReplyFrame.setLast(last); + + decodeHeaderBlock(spdySynReplyFrame, decompress(data)); + + return spdySynReplyFrame; + + case SPDY_RST_STREAM_FRAME: + if (flags != 0 || data.readableBytes() != 8) { + throw new SpdyProtocolException( + "Received invalid RST_STREAM control frame"); + } + streamID = getUnsignedInt(data, data.readerIndex()); + int statusCode = getSignedInt(data, data.readerIndex() + 4); + if (statusCode == 0) { + throw new SpdyProtocolException( + "Received invalid RST_STREAM status code"); + } + + return new DefaultSpdyRstStreamFrame(streamID, statusCode); + + case SPDY_SETTINGS_FRAME: + if (data.readableBytes() < 4) { + throw new SpdyProtocolException( + "Received invalid SETTINGS control frame"); + } + // Each ID/Value entry is 8 bytes + // The number of entries cannot exceed SPDY_MAX_LENGTH / 8; + int numEntries = getUnsignedInt(data, data.readerIndex()); + if ((numEntries > (SPDY_MAX_LENGTH - 4) / 8) || + (data.readableBytes() != numEntries * 8 + 4)) { + throw new SpdyProtocolException( + "Received invalid SETTINGS control frame"); + } + data.skipBytes(4); + + SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame(); + + boolean clear = (flags & SPDY_SETTINGS_CLEAR) != 0; + spdySettingsFrame.setClearPreviouslyPersistedSettings(clear); + + for (int i = 0; i < numEntries; i ++) { + // Chromium Issue 79156 + // SPDY setting ids are not written in network byte order + // Read id assuming the architecture is little endian + int ID = (data.readByte() & 0xFF) | + (data.readByte() & 0xFF) << 8 | + (data.readByte() & 0xFF) << 16; + byte ID_flags = data.readByte(); + int value = getSignedInt(data, data.readerIndex()); + data.skipBytes(4); + + if (!(spdySettingsFrame.isSet(ID))) { + boolean persistVal = (ID_flags & SPDY_SETTINGS_PERSIST_VALUE) != 0; + boolean persisted = (ID_flags & SPDY_SETTINGS_PERSISTED) != 0; + spdySettingsFrame.setValue(ID, value, persistVal, persisted); + } + } + + return spdySettingsFrame; + + case SPDY_NOOP_FRAME: + if (data.readableBytes() != 0) { + throw new SpdyProtocolException( + "Received invalid NOOP control frame"); + } + + return null; + + case SPDY_PING_FRAME: + if (data.readableBytes() != 4) { + throw new SpdyProtocolException( + "Received invalid PING control frame"); + } + int ID = getSignedInt(data, data.readerIndex()); + + return new DefaultSpdyPingFrame(ID); + + case SPDY_GOAWAY_FRAME: + if (data.readableBytes() != 4) { + throw new SpdyProtocolException( + "Received invalid GOAWAY control frame"); + } + int lastGoodStreamID = getUnsignedInt(data, data.readerIndex()); + + return new DefaultSpdyGoAwayFrame(lastGoodStreamID); + + case SPDY_HEADERS_FRAME: + // Protocol allows length 4 frame when there are no name/value pairs + if (data.readableBytes() == 4) { + streamID = getUnsignedInt(data, data.readerIndex()); + return new DefaultSpdyHeadersFrame(streamID); + } + + if (data.readableBytes() < 8) { + throw new SpdyProtocolException( + "Received invalid HEADERS control frame"); + } + streamID = getUnsignedInt(data, data.readerIndex()); + data.skipBytes(6); + + SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamID); + + decodeHeaderBlock(spdyHeadersFrame, decompress(data)); + + return spdyHeadersFrame; + + case SPDY_WINDOW_UPDATE_FRAME: + return null; + + default: + return null; + } + } + + private ChannelBuffer decompress(ChannelBuffer compressed) throws Exception { + if ((compressed.readableBytes() == 2) && + (compressed.getShort(compressed.readerIndex()) == 0)) { + return compressed; + } + headerBlockDecompressor.offer(compressed); + return headerBlockDecompressor.poll(); + } + + private void decodeHeaderBlock(SpdyHeaderBlock headerFrame, ChannelBuffer headerBlock) + throws Exception { + if (headerBlock.readableBytes() < 2) { + throw new SpdyProtocolException( + "Received invalid header block"); + } + int numEntries = getUnsignedShort(headerBlock, headerBlock.readerIndex()); + headerBlock.skipBytes(2); + for (int i = 0; i < numEntries; i ++) { + if (headerBlock.readableBytes() < 2) { + throw new SpdyProtocolException( + "Received invalid header block"); + } + int nameLength = getUnsignedShort(headerBlock, headerBlock.readerIndex()); + headerBlock.skipBytes(2); + if (nameLength == 0) { + headerFrame.setInvalid(); + return; + } + if (headerBlock.readableBytes() < nameLength) { + throw new SpdyProtocolException( + "Received invalid header block"); + } + byte[] nameBytes = new byte[nameLength]; + headerBlock.readBytes(nameBytes); + String name = new String(nameBytes, "UTF-8"); + if (headerFrame.containsHeader(name)) { + throw new SpdyProtocolException( + "Received duplicate header name: " + name); + } + if (headerBlock.readableBytes() < 2) { + throw new SpdyProtocolException( + "Received invalid header block"); + } + int valueLength = getUnsignedShort(headerBlock, headerBlock.readerIndex()); + headerBlock.skipBytes(2); + if (valueLength == 0) { + headerFrame.setInvalid(); + return; + } + if (headerBlock.readableBytes() < valueLength) { + throw new SpdyProtocolException( + "Received invalid header block"); + } + byte[] valueBytes = new byte[valueLength]; + headerBlock.readBytes(valueBytes); + int index = 0; + int offset = 0; + while (index < valueBytes.length) { + while (index < valueBytes.length && valueBytes[index] != (byte) 0) { + index ++; + } + if (index < valueBytes.length && valueBytes[index + 1] == (byte) 0) { + // Received multiple, in-sequence NULL characters + headerFrame.setInvalid(); + return; + } + String value = new String(valueBytes, offset, index - offset, "UTF-8"); + headerFrame.addHeader(name, value); + index ++; + offset = index; + } + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameEncoder.java new file mode 100644 index 0000000000..19e51fea4c --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyFrameEncoder.java @@ -0,0 +1,272 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.nio.ByteOrder; +import java.util.Set; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.compression.ZlibEncoder; +import io.netty.handler.codec.embedder.EncoderEmbedder; +import io.netty.handler.codec.oneone.OneToOneEncoder; + +import static io.netty.handler.codec.spdy.SpdyCodecUtil.*; + +/** + * Encodes a SPDY Data or Control Frame into a {@link ChannelBuffer}. + */ +public class SpdyFrameEncoder extends OneToOneEncoder { + + private final EncoderEmbedder headerBlockCompressor = + new EncoderEmbedder(new ZlibEncoder(9, SPDY_DICT)); + + public SpdyFrameEncoder() { + super(); + } + + @Override + protected Object encode( + ChannelHandlerContext ctx, Channel channel, Object msg) + throws Exception { + + if (msg instanceof SpdyDataFrame) { + + SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; + ChannelBuffer data = spdyDataFrame.getData(); + byte flags = spdyDataFrame.isLast() ? SPDY_DATA_FLAG_FIN : 0; + if (spdyDataFrame.isCompressed()) { + flags |= SPDY_DATA_FLAG_COMPRESS; + } + ChannelBuffer header = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE); + header.writeInt(spdyDataFrame.getStreamID() & 0x7FFFFFFF); + header.writeByte(flags); + header.writeMedium(data.readableBytes()); + return ChannelBuffers.wrappedBuffer(header, data); + + } else if (msg instanceof SpdySynStreamFrame) { + + SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; + ChannelBuffer data = compressHeaderBlock( + encodeHeaderBlock(spdySynStreamFrame)); + byte flags = spdySynStreamFrame.isLast() ? SPDY_FLAG_FIN : 0; + if (spdySynStreamFrame.isUnidirectional()) { + flags |= SPDY_FLAG_UNIDIRECTIONAL; + } + int headerBlockLength = data.readableBytes(); + int length = (headerBlockLength == 0) ? 12 : 10 + headerBlockLength; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_SYN_STREAM_FRAME); + frame.writeByte(flags); + frame.writeMedium(length); + frame.writeInt(spdySynStreamFrame.getStreamID()); + frame.writeInt(spdySynStreamFrame.getAssociatedToStreamID()); + frame.writeShort(((short) spdySynStreamFrame.getPriority()) << 14); + if (data.readableBytes() == 0) { + frame.writeShort(0); + } + return ChannelBuffers.wrappedBuffer(frame, data); + + } else if (msg instanceof SpdySynReplyFrame) { + + SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; + ChannelBuffer data = compressHeaderBlock( + encodeHeaderBlock(spdySynReplyFrame)); + byte flags = spdySynReplyFrame.isLast() ? SPDY_FLAG_FIN : 0; + int headerBlockLength = data.readableBytes(); + int length = (headerBlockLength == 0) ? 8 : 6 + headerBlockLength; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_SYN_REPLY_FRAME); + frame.writeByte(flags); + frame.writeMedium(length); + frame.writeInt(spdySynReplyFrame.getStreamID()); + if (data.readableBytes() == 0) { + frame.writeInt(0); + } else { + frame.writeShort(0); + } + return ChannelBuffers.wrappedBuffer(frame, data); + + } else if (msg instanceof SpdyRstStreamFrame) { + + SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 8); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_RST_STREAM_FRAME); + frame.writeInt(8); + frame.writeInt(spdyRstStreamFrame.getStreamID()); + frame.writeInt(spdyRstStreamFrame.getStatus().getCode()); + return frame; + + } else if (msg instanceof SpdySettingsFrame) { + + SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; + byte flags = spdySettingsFrame.clearPreviouslyPersistedSettings() ? + SPDY_SETTINGS_CLEAR : 0; + Set IDs = spdySettingsFrame.getIDs(); + int numEntries = IDs.size(); + int length = 4 + numEntries * 8; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_SETTINGS_FRAME); + frame.writeByte(flags); + frame.writeMedium(length); + frame.writeInt(numEntries); + for (Integer ID: IDs) { + int id = ID.intValue(); + byte ID_flags = (byte) 0; + if (spdySettingsFrame.persistValue(id)) { + ID_flags |= SPDY_SETTINGS_PERSIST_VALUE; + } + if (spdySettingsFrame.isPersisted(id)) { + ID_flags |= SPDY_SETTINGS_PERSISTED; + } + // Chromium Issue 79156 + // SPDY setting ids are not written in network byte order + // Write id assuming the architecture is little endian + frame.writeByte((id >> 0) & 0xFF); + frame.writeByte((id >> 8) & 0xFF); + frame.writeByte((id >> 16) & 0xFF); + frame.writeByte(ID_flags); + frame.writeInt(spdySettingsFrame.getValue(id)); + } + return frame; + + } else if (msg instanceof SpdyNoOpFrame) { + + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_NOOP_FRAME); + frame.writeInt(0); + return frame; + + } else if (msg instanceof SpdyPingFrame) { + + SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_PING_FRAME); + frame.writeInt(4); + frame.writeInt(spdyPingFrame.getID()); + return frame; + + } else if (msg instanceof SpdyGoAwayFrame) { + + SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + 4); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_GOAWAY_FRAME); + frame.writeInt(4); + frame.writeInt(spdyGoAwayFrame.getLastGoodStreamID()); + return frame; + + } else if (msg instanceof SpdyHeadersFrame) { + + SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; + ChannelBuffer data = compressHeaderBlock( + encodeHeaderBlock(spdyHeadersFrame)); + int headerBlockLength = data.readableBytes(); + int length = (headerBlockLength == 0) ? 4 : 6 + headerBlockLength; + ChannelBuffer frame = ChannelBuffers.buffer( + ByteOrder.BIG_ENDIAN, SPDY_HEADER_SIZE + length); + frame.writeShort(SPDY_VERSION | 0x8000); + frame.writeShort(SPDY_HEADERS_FRAME); + frame.writeInt(length); + frame.writeInt(spdyHeadersFrame.getStreamID()); + if (data.readableBytes() != 0) { + frame.writeShort(0); + } + return ChannelBuffers.wrappedBuffer(frame, data); + } + + // Unknown message type + return msg; + } + + private ChannelBuffer encodeHeaderBlock(SpdyHeaderBlock headerFrame) + throws Exception { + Set names = headerFrame.getHeaderNames(); + int numHeaders = names.size(); + if (numHeaders == 0) { + return ChannelBuffers.EMPTY_BUFFER; + } + if (numHeaders > SPDY_MAX_NV_LENGTH) { + throw new IllegalArgumentException( + "header block contains too many headers"); + } + ChannelBuffer headerBlock = ChannelBuffers.dynamicBuffer( + ByteOrder.BIG_ENDIAN, 256); + headerBlock.writeShort(numHeaders); + for (String name: names) { + byte[] nameBytes = name.getBytes("UTF-8"); + headerBlock.writeShort(nameBytes.length); + headerBlock.writeBytes(nameBytes); + int savedIndex = headerBlock.writerIndex(); + int valueLength = 0; + headerBlock.writeShort(valueLength); + for (String value: headerFrame.getHeaders(name)) { + byte[] valueBytes = value.getBytes("UTF-8"); + headerBlock.writeBytes(valueBytes); + headerBlock.writeByte(0); + valueLength += valueBytes.length + 1; + } + valueLength --; + if (valueLength > SPDY_MAX_NV_LENGTH) { + throw new IllegalArgumentException( + "header exceeds allowable length: " + name); + } + headerBlock.setShort(savedIndex, valueLength); + headerBlock.writerIndex(headerBlock.writerIndex() - 1); + } + return headerBlock; + } + + private synchronized ChannelBuffer compressHeaderBlock( + ChannelBuffer uncompressed) throws Exception { + if (uncompressed.readableBytes() == 0) { + return ChannelBuffers.EMPTY_BUFFER; + } + headerBlockCompressor.offer(uncompressed); + return headerBlockCompressor.poll(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyGoAwayFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyGoAwayFrame.java new file mode 100644 index 0000000000..c4c7fb201d --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyGoAwayFrame.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol GOAWAY Control Frame + */ +public interface SpdyGoAwayFrame { + + /** + * Returns the Last-good-stream-ID of this frame. + */ + int getLastGoodStreamID(); + + /** + * Sets the Last-good-stream-ID of this frame. The Last-good-stream-ID + * cannot be negative. + */ + void setLastGoodStreamID(int lastGoodStreamID); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlock.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlock.java new file mode 100644 index 0000000000..a8d0486fed --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaderBlock.java @@ -0,0 +1,118 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * A SPDY Name/Value Header Block which provides common properties for + * {@link SpdySynStreamFrame}, {@link SpdySynReplyFrame}, and + * {@link SpdyHeadersFrame}. + * @see SpdyHeaders + */ +public interface SpdyHeaderBlock { + + /** + * Returns {@code true} if this header block is invalid. + * A RST_STREAM frame with code PROTOCOL_ERROR should be sent. + */ + boolean isInvalid(); + + /** + * Marks this header block as invalid. + */ + void setInvalid(); + + /** + * Returns the header value with the specified header name. If there is + * more than one header value for the specified header name, the first + * value is returned. + * + * @return the header value or {@code null} if there is no such header + */ + String getHeader(String name); + + /** + * Returns the header values with the specified header name. + * + * @return the {@link List} of header values. An empty list if there is no + * such header. + */ + List getHeaders(String name); + + /** + * Returns all header names and values that this block contains. + * + * @return the {@link List} of the header name-value pairs. An empty list + * if there is no header in this message. + */ + List> getHeaders(); + + /** + * Returns {@code true} if and only if there is a header with the specified + * header name. + */ + boolean containsHeader(String name); + + /** + * Returns the {@link Set} of all header names that this block contains. + */ + Set getHeaderNames(); + + /** + * Adds a new header with the specified name and value. + */ + void addHeader(String name, Object value); + + /** + * Sets a new header with the specified name and value. If there is an + * existing header with the same name, the existing header is removed. + */ + void setHeader(String name, Object value); + + /** + * Sets a new header with the specified name and values. If there is an + * existing header with the same name, the existing header is removed. + */ + void setHeader(String name, Iterable values); + + /** + * Removes the header with the specified name. + */ + void removeHeader(String name); + + /** + * Removes all headers from this block. + */ + void clearHeaders(); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaders.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaders.java new file mode 100644 index 0000000000..ec8adea0df --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeaders.java @@ -0,0 +1,545 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +/** + * Provides the constants for the standard SPDY HTTP header names and commonly + * used utility methods that access an {@link SpdyHeaderBlock}. + * @apiviz.sterotype static + */ +public class SpdyHeaders { + + /** + * SPDY HTTP header names + * @apiviz.sterotype static + */ + public static final class HttpNames { + /** + * {@code "method"} + */ + public static final String METHOD = "method"; + /** + * {@code "scheme"} + */ + public static final String SCHEME = "scheme"; + /** + * {@code "status"} + */ + public static final String STATUS = "status"; + /** + * {@code "url"} + */ + public static final String URL = "url"; + /** + * {@code "version"} + */ + public static final String VERSION = "version"; + + private HttpNames() { + super(); + } + } + + + /** + * Returns the header value with the specified header name. If there are + * more than one header value for the specified header name, the first + * value is returned. + * + * @return the header value or {@code null} if there is no such header + */ + public static String getHeader(SpdyHeaderBlock block, String name) { + return block.getHeader(name); + } + + /** + * Returns the header value with the specified header name. If there are + * more than one header value for the specified header name, the first + * value is returned. + * + * @return the header value or the {@code defaultValue} if there is no such + * header + */ + public static String getHeader(SpdyHeaderBlock block, String name, String defaultValue) { + String value = block.getHeader(name); + if (value == null) { + return defaultValue; + } + return value; + } + + /** + * Sets a new header with the specified name and value. If there is an + * existing header with the same name, the existing header is removed. + */ + public static void setHeader(SpdyHeaderBlock block, String name, Object value) { + block.setHeader(name, value); + } + + /** + * Sets a new header with the specified name and values. If there is an + * existing header with the same name, the existing header is removed. + */ + public static void setHeader(SpdyHeaderBlock block, String name, Iterable values) { + block.setHeader(name, values); + } + + /** + * Adds a new header with the specified name and value. + */ + public static void addHeader(SpdyHeaderBlock block, String name, Object value) { + block.addHeader(name, value); + } + + /** + * Removes the {@code "method"} header. + */ + public static void removeMethod(SpdyHeaderBlock block) { + block.removeHeader(HttpNames.METHOD); + } + + /** + * Returns the {@link HttpMethod} represented by the {@code "method"} header. + */ + public static HttpMethod getMethod(SpdyHeaderBlock block) { + try { + return HttpMethod.valueOf(block.getHeader(HttpNames.METHOD)); + } catch (Exception e) { + return null; + } + } + + /** + * Sets the {@code "method"} header. + */ + public static void setMethod(SpdyHeaderBlock block, HttpMethod method) { + block.setHeader(HttpNames.METHOD, method.getName()); + } + + /** + * Removes the {@code "scheme"} header. + */ + public static void removeScheme(SpdyHeaderBlock block) { + block.removeHeader(HttpNames.SCHEME); + } + + /** + * Returns the value of the {@code "scheme"} header. + */ + public static String getScheme(SpdyHeaderBlock block) { + return block.getHeader(HttpNames.SCHEME); + } + + /** + * Sets the {@code "scheme"} header. + */ + public static void setScheme(SpdyHeaderBlock block, String value) { + block.setHeader(HttpNames.SCHEME, value); + } + + /** + * Removes the {@code "status"} header. + */ + public static void removeStatus(SpdyHeaderBlock block) { + block.removeHeader(HttpNames.STATUS); + } + + /** + * Returns the {@link HttpResponseStatus} represented by the {@code "status"} header. + */ + public static HttpResponseStatus getStatus(SpdyHeaderBlock block) { + try { + String status = block.getHeader(HttpNames.STATUS); + int space = status.indexOf(' '); + if (space == -1) { + return HttpResponseStatus.valueOf(Integer.parseInt(status)); + } else { + int code = Integer.parseInt(status.substring(0, space)); + String reasonPhrase = status.substring(space + 1); + HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(code); + if (responseStatus.getReasonPhrase().equals(responseStatus)) { + return responseStatus; + } else { + return new HttpResponseStatus(code, reasonPhrase); + } + } + } catch (Exception e) { + return null; + } + } + + /** + * Sets the {@code "status"} header. + */ + public static void setStatus(SpdyHeaderBlock block, HttpResponseStatus status) { + block.setHeader(HttpNames.STATUS, status.toString()); + } + + /** + * Removes the {@code "url"} header. + */ + public static void removeUrl(SpdyHeaderBlock block) { + block.removeHeader(HttpNames.URL); + } + + /** + * Returns the value of the {@code "url"} header. + */ + public static String getUrl(SpdyHeaderBlock block) { + return block.getHeader(HttpNames.URL); + } + + /** + * Sets the {@code "url"} header. + */ + public static void setUrl(SpdyHeaderBlock block, String value) { + block.setHeader(HttpNames.URL, value); + } + + /** + * Removes the {@code "version"} header. + */ + public static void removeVersion(SpdyHeaderBlock block) { + block.removeHeader(HttpNames.VERSION); + } + + /** + * Returns the {@link HttpVersion} represented by the {@code "version"} header. + */ + public static HttpVersion getVersion(SpdyHeaderBlock block) { + try { + return HttpVersion.valueOf(block.getHeader(HttpNames.VERSION)); + } catch (Exception e) { + return null; + } + } + + /** + * Sets the {@code "version"} header. + */ + public static void setVersion(SpdyHeaderBlock block, HttpVersion version) { + block.setHeader(HttpNames.VERSION, version.getText()); + } + + + private static final int BUCKET_SIZE = 17; + + private static int hash(String name) { + int h = 0; + for (int i = name.length() - 1; i >= 0; i --) { + char c = name.charAt(i); + if (c >= 'A' && c <= 'Z') { + c += 32; + } + h = 31 * h + c; + } + + if (h > 0) { + return h; + } else if (h == Integer.MIN_VALUE) { + return Integer.MAX_VALUE; + } else { + return -h; + } + } + + private static boolean eq(String name1, String name2) { + int nameLen = name1.length(); + if (nameLen != name2.length()) { + return false; + } + + for (int i = nameLen - 1; i >= 0; i --) { + char c1 = name1.charAt(i); + char c2 = name2.charAt(i); + if (c1 != c2) { + if (c1 >= 'A' && c1 <= 'Z') { + c1 += 32; + } + if (c2 >= 'A' && c2 <= 'Z') { + c2 += 32; + } + if (c1 != c2) { + return false; + } + } + } + return true; + } + + private static int index(int hash) { + return hash % BUCKET_SIZE; + } + + private final Entry[] entries = new Entry[BUCKET_SIZE]; + private final Entry head = new Entry(-1, null, null); + + SpdyHeaders() { + head.before = head.after = head; + } + + void addHeader(final String name, final Object value) { + String lowerCaseName = name.toLowerCase(); + SpdyCodecUtil.validateHeaderName(lowerCaseName); + String strVal = toString(value); + SpdyCodecUtil.validateHeaderValue(strVal); + int h = hash(lowerCaseName); + int i = index(h); + addHeader0(h, i, lowerCaseName, strVal); + } + + private void addHeader0(int h, int i, final String name, final String value) { + // Update the hash table. + Entry e = entries[i]; + Entry newEntry; + entries[i] = newEntry = new Entry(h, name, value); + newEntry.next = e; + + // Update the linked list. + newEntry.addBefore(head); + } + + void removeHeader(final String name) { + if (name == null) { + throw new NullPointerException("name"); + } + String lowerCaseName = name.toLowerCase(); + int h = hash(lowerCaseName); + int i = index(h); + removeHeader0(h, i, lowerCaseName); + } + + private void removeHeader0(int h, int i, String name) { + Entry e = entries[i]; + if (e == null) { + return; + } + + for (;;) { + if (e.hash == h && eq(name, e.key)) { + e.remove(); + Entry next = e.next; + if (next != null) { + entries[i] = next; + e = next; + } else { + entries[i] = null; + return; + } + } else { + break; + } + } + + for (;;) { + Entry next = e.next; + if (next == null) { + break; + } + if (next.hash == h && eq(name, next.key)) { + e.next = next.next; + next.remove(); + } else { + e = next; + } + } + } + + void setHeader(final String name, final Object value) { + String lowerCaseName = name.toLowerCase(); + SpdyCodecUtil.validateHeaderName(lowerCaseName); + String strVal = toString(value); + SpdyCodecUtil.validateHeaderValue(strVal); + int h = hash(lowerCaseName); + int i = index(h); + removeHeader0(h, i, lowerCaseName); + addHeader0(h, i, lowerCaseName, strVal); + } + + void setHeader(final String name, final Iterable values) { + if (values == null) { + throw new NullPointerException("values"); + } + + String lowerCaseName = name.toLowerCase(); + SpdyCodecUtil.validateHeaderName(lowerCaseName); + + int h = hash(lowerCaseName); + int i = index(h); + + removeHeader0(h, i, lowerCaseName); + for (Object v: values) { + if (v == null) { + break; + } + String strVal = toString(v); + SpdyCodecUtil.validateHeaderValue(strVal); + addHeader0(h, i, lowerCaseName, strVal); + } + } + + void clearHeaders() { + for (int i = 0; i < entries.length; i ++) { + entries[i] = null; + } + head.before = head.after = head; + } + + String getHeader(final String name) { + if (name == null) { + throw new NullPointerException("name"); + } + + int h = hash(name); + int i = index(h); + Entry e = entries[i]; + while (e != null) { + if (e.hash == h && eq(name, e.key)) { + return e.value; + } + + e = e.next; + } + return null; + } + + List getHeaders(final String name) { + if (name == null) { + throw new NullPointerException("name"); + } + + LinkedList values = new LinkedList(); + + int h = hash(name); + int i = index(h); + Entry e = entries[i]; + while (e != null) { + if (e.hash == h && eq(name, e.key)) { + values.addFirst(e.value); + } + e = e.next; + } + return values; + } + + List> getHeaders() { + List> all = + new LinkedList>(); + + Entry e = head.after; + while (e != head) { + all.add(e); + e = e.after; + } + return all; + } + + boolean containsHeader(String name) { + return getHeader(name) != null; + } + + Set getHeaderNames() { + Set names = new TreeSet(); + + Entry e = head.after; + while (e != head) { + names.add(e.key); + e = e.after; + } + return names; + } + + private static String toString(Object value) { + if (value == null) { + return null; + } + return value.toString(); + } + + private static final class Entry implements Map.Entry { + final int hash; + final String key; + String value; + Entry next; + Entry before, after; + + Entry(int hash, String key, String value) { + this.hash = hash; + this.key = key; + this.value = value; + } + + void remove() { + before.after = after; + after.before = before; + } + + void addBefore(Entry e) { + after = e; + before = e.before; + before.after = this; + after.before = this; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + public String setValue(String value) { + if (value == null) { + throw new NullPointerException("value"); + } + SpdyCodecUtil.validateHeaderValue(value); + String oldValue = this.value; + this.value = value; + return oldValue; + } + + @Override + public String toString() { + return key + "=" + value; + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeadersFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeadersFrame.java new file mode 100644 index 0000000000..ecfbf6017c --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyHeadersFrame.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol HEADERS Control Frame + */ +public interface SpdyHeadersFrame extends SpdyHeaderBlock { + + /** + * Returns the Stream-ID of this frame. + */ + int getStreamID(); + + /** + * Sets the Stream-ID of this frame. The Stream-ID must be positive. + */ + void setStreamID(int streamID); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyNoOpFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyNoOpFrame.java new file mode 100644 index 0000000000..1652344fd7 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyNoOpFrame.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol NOOP Control Frame + */ +public interface SpdyNoOpFrame { +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyPingFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyPingFrame.java new file mode 100644 index 0000000000..48b7bc65ec --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyPingFrame.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol PING Control Frame + */ +public interface SpdyPingFrame { + + /** + * Returns the ID of this frame. + */ + int getID(); + + /** + * Sets the ID of this frame. + */ + void setID(int ID); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyProtocolException.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyProtocolException.java new file mode 100644 index 0000000000..508354fb1d --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyProtocolException.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * An {@link Exception} which is thrown when the received frame cannot + * be decoded by the {@link SpdyFrameDecoder}. + * @apiviz.exclude + */ +public class SpdyProtocolException extends Exception { + + /** + * Creates a new instance. + */ + public SpdyProtocolException() { + super(); + } + + /** + * Creates a new instance. + */ + public SpdyProtocolException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new instance. + */ + public SpdyProtocolException(String message) { + super(message); + } + + /** + * Creates a new instance. + */ + public SpdyProtocolException(Throwable cause) { + super(cause); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyRstStreamFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyRstStreamFrame.java new file mode 100644 index 0000000000..0cfc8b6945 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyRstStreamFrame.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol RST_STREAM Control Frame + */ +public interface SpdyRstStreamFrame { + + /** + * Returns the Stream-ID of this frame. + */ + int getStreamID(); + + /** + * Sets the Stream-ID of this frame. The Stream-ID must be positive. + */ + void setStreamID(int streamID); + + /** + * Returns the status of this frame. + */ + SpdyStreamStatus getStatus(); + + /** + * Sets the status of this frame. + */ + void setStatus(SpdyStreamStatus status); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySession.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySession.java new file mode 100644 index 0000000000..7645b65b78 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySession.java @@ -0,0 +1,148 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +final class SpdySession { + + private final Map activeStreams = + new ConcurrentHashMap(); + + SpdySession() { + } + + public int numActiveStreams() { + return activeStreams.size(); + } + + public boolean noActiveStreams() { + return activeStreams.isEmpty(); + } + + public boolean isActiveStream(int streamID) { + return activeStreams.containsKey(new Integer(streamID)); + } + + public void acceptStream(int streamID, boolean remoteSideClosed, boolean localSideClosed) { + if (!remoteSideClosed || !localSideClosed) { + activeStreams.put(new Integer(streamID), + new StreamState(remoteSideClosed, localSideClosed)); + } + return; + } + + public void removeStream(int streamID) { + activeStreams.remove(new Integer(streamID)); + return; + } + + public boolean isRemoteSideClosed(int streamID) { + StreamState state = activeStreams.get(new Integer(streamID)); + return (state == null) || state.isRemoteSideClosed(); + } + + public void closeRemoteSide(int streamID) { + Integer StreamID = new Integer(streamID); + StreamState state = activeStreams.get(StreamID); + if (state != null) { + state.closeRemoteSide(); + if (state.isLocalSideClosed()) { + activeStreams.remove(StreamID); + } + } + } + + public boolean isLocalSideClosed(int streamID) { + StreamState state = activeStreams.get(new Integer(streamID)); + return (state == null) || state.isLocalSideClosed(); + } + + public void closeLocalSide(int streamID) { + Integer StreamID = new Integer(streamID); + StreamState state = activeStreams.get(StreamID); + if (state != null) { + state.closeLocalSide(); + if (state.isRemoteSideClosed()) { + activeStreams.remove(StreamID); + } + } + } + + public boolean hasReceivedReply(int streamID) { + StreamState state = activeStreams.get(new Integer(streamID)); + return (state != null) && state.hasReceivedReply(); + } + + public void receivedReply(int streamID) { + StreamState state = activeStreams.get(new Integer(streamID)); + if (state != null) { + state.receivedReply(); + } + } + + private static final class StreamState { + + private boolean remoteSideClosed; + private boolean localSideClosed; + private boolean receivedReply; + + public StreamState(boolean remoteSideClosed, boolean localSideClosed) { + this.remoteSideClosed = remoteSideClosed; + this.localSideClosed = localSideClosed; + } + + public boolean isRemoteSideClosed() { + return remoteSideClosed; + } + + public void closeRemoteSide() { + remoteSideClosed = true; + } + + public boolean isLocalSideClosed() { + return localSideClosed; + } + + public void closeLocalSide() { + localSideClosed = true; + } + + public boolean hasReceivedReply() { + return receivedReply; + } + + public void receivedReply() { + receivedReply = true; + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java new file mode 100644 index 0000000000..70c32c963d --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySessionHandler.java @@ -0,0 +1,512 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.net.SocketAddress; +import java.nio.channels.ClosedChannelException; +import java.util.concurrent.atomic.AtomicInteger; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelDownstreamHandler; +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.Channels; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; + +/** + * Manages streams within a SPDY session. + */ +public class SpdySessionHandler extends SimpleChannelUpstreamHandler + implements ChannelDownstreamHandler { + + private static final SpdyProtocolException PROTOCOL_EXCEPTION = new SpdyProtocolException(); + + private final SpdySession spdySession = new SpdySession(); + private volatile int lastGoodStreamID; + + private volatile int remoteConcurrentStreams; + private volatile int localConcurrentStreams; + private volatile int maxConcurrentStreams; + + private final AtomicInteger pings = new AtomicInteger(); + + private volatile boolean sentGoAwayFrame; + private volatile boolean receivedGoAwayFrame; + + private volatile ChannelFuture closeSessionFuture; + + private final boolean server; + + /** + * Creates a new session handler. + * + * @param server {@code true} if and only if this session handler should + * handle the server endpoint of the connection. + * {@code false} if and only if this session handler should + * handle the client endpoint of the connection. + */ + public SpdySessionHandler(boolean server) { + super(); + this.server = server; + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + + Object msg = e.getMessage(); + if (msg instanceof SpdyDataFrame) { + + /* + * SPDY Data frame processing requirements: + * + * If an endpoint receives a data frame for a Stream-ID which does not exist, + * it must return a RST_STREAM with error code INVALID_STREAM for the Stream-ID. + * + * If an endpoint which created the stream receives a data frame before receiving + * a SYN_REPLY on that stream, it is a protocol error, and the receiver should + * close the connection immediately. + * + * If an endpoint receives multiple data frames for invalid Stream-IDs, + * it may terminate the session. + * + * If an endpoint refuses a stream it must ignore any data frames for that stream. + * + * If an endpoint receives data on a stream which has already been torn down, + * it must ignore the data received after the teardown. + */ + + SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; + int streamID = spdyDataFrame.getStreamID(); + + // Check if we received a data frame for a Stream-ID which is not open + if (spdySession.isRemoteSideClosed(streamID)) { + if (!sentGoAwayFrame) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.INVALID_STREAM); + } + return; + } + + // Check if we received a data frame before receiving a SYN_REPLY + if (!isRemoteInitiatedID(streamID) && !spdySession.hasReceivedReply(streamID)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + return; + } + + if (spdyDataFrame.isLast()) { + // Close remote side of stream + halfCloseStream(streamID, true); + } + + } else if (msg instanceof SpdySynStreamFrame) { + + /* + * SPDY SYN_STREAM frame processing requirements: + * + * If an endpoint receives a SYN_STREAM with a Stream-ID that is not monotonically + * increasing, it must issue a session error with the status PROTOCOL_ERROR. + * + * If an endpoint receives multiple SYN_STREAM frames with the same active + * Stream-ID, it must issue a stream error with the status code PROTOCOL_ERROR. + */ + + SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; + int streamID = spdySynStreamFrame.getStreamID(); + + // Check if we received a valid SYN_STREAM frame + if (spdySynStreamFrame.isInvalid() || + !isRemoteInitiatedID(streamID) || + spdySession.isActiveStream(streamID)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + return; + } + + // Stream-IDs must be monotonically increassing + if (streamID < lastGoodStreamID) { + issueSessionError(ctx, e.getChannel(), e.getRemoteAddress()); + return; + } + + // Try to accept the stream + boolean remoteSideClosed = spdySynStreamFrame.isLast(); + boolean localSideClosed = spdySynStreamFrame.isUnidirectional(); + if (!acceptStream(streamID, remoteSideClosed, localSideClosed)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.REFUSED_STREAM); + return; + } + + } else if (msg instanceof SpdySynReplyFrame) { + + /* + * SPDY SYN_REPLY frame processing requirements: + * + * If an endpoint receives multiple SYN_REPLY frames for the same active Stream-ID + * it must issue a stream error with the status code PROTOCOL_ERROR. + */ + + SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; + int streamID = spdySynReplyFrame.getStreamID(); + + // Check if we received a valid SYN_REPLY frame + if (spdySynReplyFrame.isInvalid() || + isRemoteInitiatedID(streamID) || + spdySession.isRemoteSideClosed(streamID)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.INVALID_STREAM); + return; + } + + // Check if we have received multiple frames for the same Stream-ID + if (spdySession.hasReceivedReply(streamID)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + return; + } + + spdySession.receivedReply(streamID); + if (spdySynReplyFrame.isLast()) { + // Close remote side of stream + halfCloseStream(streamID, true); + } + + } else if (msg instanceof SpdyRstStreamFrame) { + + /* + * SPDY RST_STREAM frame processing requirements: + * + * After receiving a RST_STREAM on a stream, the receiver must not send additional + * frames on that stream. + */ + + SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; + removeStream(spdyRstStreamFrame.getStreamID()); + + } else if (msg instanceof SpdySettingsFrame) { + + /* + * Only concerned with MAX_CONCURRENT_STREAMS + */ + + SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; + updateConcurrentStreams(spdySettingsFrame, true); + + } else if (msg instanceof SpdyPingFrame) { + + /* + * SPDY PING frame processing requirements: + * + * Receivers of a PING frame should send an identical frame to the sender + * as soon as possible. + * + * Receivers of a PING frame must ignore frames that it did not initiate + */ + + SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; + + if (isRemoteInitiatedID(spdyPingFrame.getID())) { + Channels.write(ctx, Channels.future(e.getChannel()), spdyPingFrame, e.getRemoteAddress()); + return; + } + + // Note: only checks that there are outstanding pings since uniqueness is not inforced + if (pings.get() == 0) { + return; + } + pings.getAndDecrement(); + + } else if (msg instanceof SpdyGoAwayFrame) { + + receivedGoAwayFrame = true; + + } else if (msg instanceof SpdyHeadersFrame) { + + SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; + int streamID = spdyHeadersFrame.getStreamID(); + + // Check if we received a valid HEADERS frame + if (spdyHeadersFrame.isInvalid()) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.PROTOCOL_ERROR); + return; + } + + if (spdySession.isRemoteSideClosed(streamID)) { + issueStreamError(ctx, e, streamID, SpdyStreamStatus.INVALID_STREAM); + return; + } + } + + super.messageReceived(ctx, e); + } + + public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent evt) + throws Exception { + if (evt instanceof ChannelStateEvent) { + ChannelStateEvent e = (ChannelStateEvent) evt; + switch (e.getState()) { + case OPEN: + case CONNECTED: + case BOUND: + if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) { + sendGoAwayFrame(ctx, e); + return; + } + } + } + if (!(evt instanceof MessageEvent)) { + ctx.sendDownstream(evt); + return; + } + + MessageEvent e = (MessageEvent) evt; + Object msg = e.getMessage(); + + if (msg instanceof SpdyDataFrame) { + + SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; + int streamID = spdyDataFrame.getStreamID(); + + if (spdySession.isLocalSideClosed(streamID)) { + e.getFuture().setFailure(PROTOCOL_EXCEPTION); + return; + } + + if (spdyDataFrame.isLast()) { + halfCloseStream(streamID, false); + } + + } else if (msg instanceof SpdySynStreamFrame) { + + SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; + boolean remoteSideClosed = spdySynStreamFrame.isUnidirectional(); + boolean localSideClosed = spdySynStreamFrame.isLast(); + if (!acceptStream(spdySynStreamFrame.getStreamID(), remoteSideClosed, localSideClosed)) { + e.getFuture().setFailure(PROTOCOL_EXCEPTION); + return; + } + + } else if (msg instanceof SpdySynReplyFrame) { + + SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; + int streamID = spdySynReplyFrame.getStreamID(); + + if (!isRemoteInitiatedID(streamID) || spdySession.isLocalSideClosed(streamID)) { + e.getFuture().setFailure(PROTOCOL_EXCEPTION); + return; + } + + if (spdySynReplyFrame.isLast()) { + halfCloseStream(streamID, false); + } + + } else if (msg instanceof SpdyRstStreamFrame) { + + SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; + removeStream(spdyRstStreamFrame.getStreamID()); + + } else if (msg instanceof SpdySettingsFrame) { + + SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; + updateConcurrentStreams(spdySettingsFrame, false); + + } else if (msg instanceof SpdyPingFrame) { + + SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; + if (isRemoteInitiatedID(spdyPingFrame.getID())) { + e.getFuture().setFailure(new IllegalArgumentException( + "invalid PING ID: " + spdyPingFrame.getID())); + return; + } + pings.getAndIncrement(); + + } else if (msg instanceof SpdyGoAwayFrame) { + + // Should send a CLOSE ChannelStateEvent + e.getFuture().setFailure(PROTOCOL_EXCEPTION); + return; + + } else if (msg instanceof SpdyHeadersFrame) { + + SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; + int streamID = spdyHeadersFrame.getStreamID(); + + if (spdySession.isLocalSideClosed(streamID)) { + e.getFuture().setFailure(PROTOCOL_EXCEPTION); + return; + } + } + + ctx.sendDownstream(evt); + } + + /* + * Error Handling + */ + + private void issueSessionError( + ChannelHandlerContext ctx, Channel channel, SocketAddress remoteAddress) { + + ChannelFuture future = sendGoAwayFrame(ctx, channel, remoteAddress); + future.addListener(ChannelFutureListener.CLOSE); + } + + // Send a RST_STREAM frame in response to an incoming MessageEvent + // Only called in the upstream direction + private void issueStreamError( + ChannelHandlerContext ctx, MessageEvent e, int streamID, SpdyStreamStatus status) { + + removeStream(streamID); + SpdyRstStreamFrame spdyRstStreamFrame = new DefaultSpdyRstStreamFrame(streamID, status); + Channels.write(ctx, Channels.future(e.getChannel()), spdyRstStreamFrame, e.getRemoteAddress()); + } + + /* + * Helper functions + */ + + private boolean isServerID(int ID) { + return ID % 2 == 0; + } + + private boolean isRemoteInitiatedID(int ID) { + boolean serverID = isServerID(ID); + return (server && !serverID) || (!server && serverID); + } + + private synchronized void updateConcurrentStreams(SpdySettingsFrame settings, boolean remote) { + int newConcurrentStreams = settings.getValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS); + if (remote) { + remoteConcurrentStreams = newConcurrentStreams; + } else { + localConcurrentStreams = newConcurrentStreams; + } + if (localConcurrentStreams == remoteConcurrentStreams) { + maxConcurrentStreams = localConcurrentStreams; + return; + } + if (localConcurrentStreams == 0) { + maxConcurrentStreams = remoteConcurrentStreams; + return; + } + if (remoteConcurrentStreams == 0) { + maxConcurrentStreams = localConcurrentStreams; + return; + } + if (localConcurrentStreams > remoteConcurrentStreams) { + maxConcurrentStreams = remoteConcurrentStreams; + } else { + maxConcurrentStreams = localConcurrentStreams; + } + } + + // need to synchronize accesses to sentGoAwayFrame and lastGoodStreamID + private synchronized boolean acceptStream( + int streamID, boolean remoteSideClosed, boolean localSideClosed) { + // Cannot initiate any new streams after receiving or sending GOAWAY + if (receivedGoAwayFrame || sentGoAwayFrame) { + return false; + } + if ((maxConcurrentStreams != 0) && + (spdySession.numActiveStreams() >= maxConcurrentStreams)) { + return false; + } + spdySession.acceptStream(streamID, remoteSideClosed, localSideClosed); + if (isRemoteInitiatedID(streamID)) { + lastGoodStreamID = streamID; + } + return true; + } + + private void halfCloseStream(int streamID, boolean remote) { + if (remote) { + spdySession.closeRemoteSide(streamID); + } else { + spdySession.closeLocalSide(streamID); + } + if ((closeSessionFuture != null) && spdySession.noActiveStreams()) { + closeSessionFuture.setSuccess(); + } + } + + private void removeStream(int streamID) { + spdySession.removeStream(streamID); + if ((closeSessionFuture != null) && spdySession.noActiveStreams()) { + closeSessionFuture.setSuccess(); + } + } + + private void sendGoAwayFrame(ChannelHandlerContext ctx, ChannelStateEvent e) { + // Avoid NotYetConnectedException + if (!e.getChannel().isConnected()) { + ctx.sendDownstream(e); + return; + } + + ChannelFuture future = sendGoAwayFrame(ctx, e.getChannel(), null); + if (spdySession.noActiveStreams()) { + future.addListener(new ClosingChannelFutureListener(ctx, e)); + } else { + closeSessionFuture = Channels.future(e.getChannel()); + closeSessionFuture.addListener(new ClosingChannelFutureListener(ctx, e)); + } + } + + private synchronized ChannelFuture sendGoAwayFrame( + ChannelHandlerContext ctx, Channel channel, SocketAddress remoteAddress) { + if (!sentGoAwayFrame) { + sentGoAwayFrame = true; + ChannelFuture future = Channels.future(channel); + Channels.write(ctx, future, new DefaultSpdyGoAwayFrame(lastGoodStreamID)); + return future; + } + return Channels.succeededFuture(channel); + } + + private static final class ClosingChannelFutureListener implements ChannelFutureListener { + + private final ChannelHandlerContext ctx; + private final ChannelStateEvent e; + + ClosingChannelFutureListener(ChannelHandlerContext ctx, ChannelStateEvent e) { + this.ctx = ctx; + this.e = e; + } + + public void operationComplete(ChannelFuture sentGoAwayFuture) throws Exception { + if (!(sentGoAwayFuture.getCause() instanceof ClosedChannelException)) { + Channels.close(ctx, e.getFuture()); + } else { + e.getFuture().setSuccess(); + } + } + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySettingsFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySettingsFrame.java new file mode 100644 index 0000000000..39751cfcb9 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySettingsFrame.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.Set; + +/** + * A SPDY Protocol SETTINGS Control Frame + */ +public interface SpdySettingsFrame { + + int SETTINGS_UPLOAD_BANDWIDTH = 1; + int SETTINGS_DOWNLOAD_BANDWIDTH = 2; + int SETTINGS_ROUND_TRIP_TIME = 3; + int SETTINGS_MAX_CONCURRENT_STREAMS = 4; + int SETTINGS_CURRENT_CWND = 5; + int SETTINGS_DOWNLOAD_RETRANS_RATE = 6; + int SETTINGS_INITIAL_WINDOW_SIZE = 7; + + /** + * Returns a {@code Set} of the setting IDs. + * The set's iterator will return the IDs in ascending order. + */ + Set getIDs(); + + /** + * Returns {@code true} if the setting ID has a value. + */ + boolean isSet(int ID); + + /** + * Returns the value of the setting ID. + * Returns -1 if the setting ID is not set. + */ + int getValue(int ID); + + /** + * Sets the value of the setting ID. + * The ID must be positive and cannot exceeed 16777215. + */ + void setValue(int ID, int value); + + /** + * Sets the value of the setting ID. + * Sets if the setting should be persisted (should only be set by the server). + * Sets if the setting is persisted (should only be set by the client). + * The ID must be positive and cannot exceed 16777215. + */ + void setValue(int ID, int value, boolean persistVal, boolean persisted); + + /** + * Removes the value of the setting ID. + * Removes all persistance information for the setting. + */ + void removeValue(int ID); + + /** + * Returns {@code true} if this setting should be persisted. + * Returns {@code false} if this setting should not be persisted + * or if the setting ID has no value. + */ + boolean persistValue(int ID); + + /** + * Sets if this setting should be persisted. + * Has no effect if the setting ID has no value. + */ + void setPersistValue(int ID, boolean persistValue); + + /** + * Returns {@code true} if this setting is persisted. + * Returns {@code false} if this setting should not be persisted + * or if the setting ID has no value. + */ + boolean isPersisted(int ID); + + /** + * Sets if this setting is persisted. + * Has no effect if the setting ID has no value. + */ + void setPersisted(int ID, boolean persisted); + + /** + * Returns {@code true} if previously persisted settings should be cleared. + */ + boolean clearPreviouslyPersistedSettings(); + + /** + * Sets if previously persisted settings should be cleared. + */ + void setClearPreviouslyPersistedSettings(boolean clear); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyStreamStatus.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyStreamStatus.java new file mode 100644 index 0000000000..51272629d8 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdyStreamStatus.java @@ -0,0 +1,170 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * The SPDY stream status code and its description. + * @apiviz.exclude + */ +public class SpdyStreamStatus implements Comparable { + + /** + * 1 Protocol Error + */ + public static final SpdyStreamStatus PROTOCOL_ERROR = + new SpdyStreamStatus(1, "PROTOCOL_ERROR"); + + /** + * 2 Invalid Stream + */ + public static final SpdyStreamStatus INVALID_STREAM = + new SpdyStreamStatus(2, "INVALID_STREAM"); + + /** + * 3 Refused Stream + */ + public static final SpdyStreamStatus REFUSED_STREAM = + new SpdyStreamStatus(3, "REFUSED_STREAM"); + + /** + * 4 Unsupported Version + */ + public static final SpdyStreamStatus UNSUPPORTED_VERSION = + new SpdyStreamStatus(4, "UNSUPPORTED_VERSION"); + + /** + * 5 Cancel + */ + public static final SpdyStreamStatus CANCEL = + new SpdyStreamStatus(5, "CANCEL"); + + /** + * 6 Internal Error + */ + public static final SpdyStreamStatus INTERNAL_ERROR = + new SpdyStreamStatus(6, "INTERNAL_ERROR"); + + /** + * 7 Flow Control Error + */ + public static final SpdyStreamStatus FLOW_CONTROL_ERROR = + new SpdyStreamStatus(7, "FLOW_CONTROL_ERROR"); + + /** + * Returns the {@link SpdyStreamStatus} represented by the specified code. + * If the specified code is a defined SPDY status code, a cached instance + * will be returned. Otherwise, a new instance will be returned. + */ + public static SpdyStreamStatus valueOf(int code) { + if (code == 0) { + throw new IllegalArgumentException( + "0 is not a valid status code for a RST_STREAM"); + } + + switch (code) { + case 1: + return PROTOCOL_ERROR; + case 2: + return INVALID_STREAM; + case 3: + return REFUSED_STREAM; + case 4: + return UNSUPPORTED_VERSION; + case 5: + return CANCEL; + case 6: + return INTERNAL_ERROR; + case 7: + return FLOW_CONTROL_ERROR; + } + + return new SpdyStreamStatus(code, "UNKNOWN (" + code + ')'); + } + + private final int code; + + private final String statusPhrase; + + /** + * Creates a new instance with the specified {@code code} and its + * {@code statusPhrase}. + */ + public SpdyStreamStatus(int code, String statusPhrase) { + if (code == 0) { + throw new IllegalArgumentException( + "0 is not a valid status code for a RST_STREAM"); + } + + if (statusPhrase == null) { + throw new NullPointerException("statusPhrase"); + } + + this.code = code; + this.statusPhrase = statusPhrase; + } + + /** + * Returns the code of this status. + */ + public int getCode() { + return code; + } + + /** + * Returns the status phrase of this status. + */ + public String getStatusPhrase() { + return statusPhrase; + } + + @Override + public int hashCode() { + return getCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SpdyStreamStatus)) { + return false; + } + + return getCode() == ((SpdyStreamStatus) o).getCode(); + } + + @Override + public String toString() { + return getStatusPhrase(); + } + + public int compareTo(SpdyStreamStatus o) { + return getCode() - o.getCode(); + } +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynReplyFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynReplyFrame.java new file mode 100644 index 0000000000..e24bc844d7 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynReplyFrame.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol SYN_REPLY Control Frame + */ +public interface SpdySynReplyFrame extends SpdyHeaderBlock { + + /** + * Returns the Stream-ID of this frame. + */ + int getStreamID(); + + /** + * Sets the Stream-ID of this frame. The Stream-ID must be positive. + */ + void setStreamID(int streamID); + + /** + * Returns {@code true} if this frame is the last frame to be transmitted + * on the stream. + */ + boolean isLast(); + + /** + * Sets if this frame is the last frame to be transmitted on the stream. + */ + void setLast(boolean last); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynStreamFrame.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynStreamFrame.java new file mode 100644 index 0000000000..b8aa7de181 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/SpdySynStreamFrame.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +/** + * A SPDY Protocol SYN_STREAM Control Frame + */ +public interface SpdySynStreamFrame extends SpdyHeaderBlock { + + /** + * Returns the Stream-ID of this frame. + */ + int getStreamID(); + + /** + * Sets the Stream-ID of this frame. The Stream-ID must be positive. + */ + void setStreamID(int streamID); + + /** + * Returns the Associated-To-Stream-ID of this frame. + */ + int getAssociatedToStreamID(); + + /** + * Sets the Associated-To-Stream-ID of this frame. + * The Associated-To-Stream-ID cannot be negative. + */ + void setAssociatedToStreamID(int associatedToStreamID); + + /** + * Returns the priority of the stream. + */ + byte getPriority(); + + /** + * Sets the priority of the stream. + * The priority must be between 0 and 3 inclusive. + */ + void setPriority(byte priority); + + /** + * Returns {@code true} if this frame is the last frame to be transmitted + * on the stream. + */ + boolean isLast(); + + /** + * Sets if this frame is the last frame to be transmitted on the stream. + */ + void setLast(boolean last); + + /** + * Returns {@code true} if the stream created with this frame is to be + * considered half-closed to the receiver. + */ + boolean isUnidirectional(); + + /** + * Sets if the stream created with this frame is to be considered + * half-closed to the receiver. + */ + void setUnidirectional(boolean unidirectional); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/spdy/package-info.java b/codec-http/src/main/java/io/netty/handler/codec/spdy/package-info.java new file mode 100644 index 0000000000..3b97176307 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/spdy/package-info.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Encoder, decoder, session handler and their related message types for the SPDY protocol. + * + * @apiviz.exclude ^java\.lang\. + * @apiviz.exclude OneToOne(Encoder|Decoder)$ + * @apiviz.exclude \.SpdyHeaders\. + * @apiviz.exclude \.codec\.frame\. + * @apiviz.exclude \.(Simple)?Channel[A-Za-z]*Handler$ + * @apiviz.exclude \.Default + * @apiviz.exclude \.SpdyFrameCodec$ + */ +package io.netty.handler.codec.spdy; diff --git a/src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java similarity index 99% rename from src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java rename to codec-http/src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java index b9499381d0..b853328e70 100644 --- a/src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/CookieDecoderTest.java @@ -28,8 +28,6 @@ import java.util.Set; import org.junit.Test; -/** - */ public class CookieDecoderTest { @Test public void testDecodingSingleCookieV0() { diff --git a/src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java similarity index 99% rename from src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java rename to codec-http/src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java index a924ac0d06..b274e44e35 100644 --- a/src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/CookieEncoderTest.java @@ -24,9 +24,6 @@ import java.util.Date; import org.junit.Test; - -/** - */ public class CookieEncoderTest { @Test public void testEncodingSingleCookieV0() { diff --git a/src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java similarity index 99% rename from src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java rename to codec-http/src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java index cb3945a1d6..a2d75940cf 100644 --- a/src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/DefaultHttpMessageTest.java @@ -18,8 +18,6 @@ package io.netty.handler.codec.http; import org.junit.Assert; import org.junit.Test; -/** - */ public class DefaultHttpMessageTest { @Test diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java new file mode 100644 index 0000000000..0f103abd33 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/http/HttpContentCompressorTest.java @@ -0,0 +1,62 @@ +/* +* Copyright 2011 The Netty Project +* +* The Netty Project licenses this file to you under the Apache License, +* version 2.0 (the "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +*/ +package io.netty.handler.codec.http; + +import org.junit.Assert; +import org.junit.Test; + +import io.netty.handler.codec.compression.ZlibWrapper; + +public class HttpContentCompressorTest { + @Test + public void testGetTargetContentEncoding() throws Exception { + HttpContentCompressor compressor = new HttpContentCompressor(); + + String[] tests = { + // Accept-Encoding -> Content-Encoding + "", null, + "*", "gzip", + "*;q=0.0", null, + "gzip", "gzip", + "compress, gzip;q=0.5", "gzip", + "gzip; q=0.5, identity", "gzip", + "gzip ; q=0.1", "gzip", + "gzip; q=0, deflate", "deflate", + " defalte ; q=0 , *;q=0.5", "gzip", + }; + for (int i = 0; i < tests.length; i += 2) { + String acceptEncoding = tests[i]; + String contentEncoding = tests[i + 1]; + ZlibWrapper targetWrapper = compressor.determineWrapper(acceptEncoding); + String targetEncoding = null; + if (targetWrapper != null) { + switch (targetWrapper) { + case GZIP: + targetEncoding = "gzip"; + break; + case ZLIB: + targetEncoding = "deflate"; + break; + default: + if (targetWrapper != null) { + Assert.fail(); + } + } + } + Assert.assertEquals(contentEncoding, targetEncoding); + } + } +} diff --git a/src/test/java/io/netty/handler/codec/http/HttpHeaderDateFormatTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/HttpHeaderDateFormatTest.java similarity index 100% rename from src/test/java/io/netty/handler/codec/http/HttpHeaderDateFormatTest.java rename to codec-http/src/test/java/io/netty/handler/codec/http/HttpHeaderDateFormatTest.java diff --git a/src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java similarity index 86% rename from src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java rename to codec-http/src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java index 1a3e580ea7..14f93c73c0 100644 --- a/src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/QueryStringDecoderTest.java @@ -15,12 +15,13 @@ */ package io.netty.handler.codec.http; +import java.util.List; +import java.util.Map; + import io.netty.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; -/** - */ public class QueryStringDecoderTest { @Test @@ -93,6 +94,33 @@ public class QueryStringDecoderTest { assertQueryString("/foo?a=b&c=d", "/foo?a=b&c=d"); assertQueryString("/foo?a=1&a=&a=", "/foo?a=1&a&a="); } + + @Test + public void testHashDos() throws Exception { + StringBuilder buf = new StringBuilder(); + buf.append('?'); + for (int i = 0; i < 65536; i ++) { + buf.append('k'); + buf.append(i); + buf.append("=v"); + buf.append(i); + buf.append('&'); + } + Assert.assertEquals(1024, new QueryStringDecoder(buf.toString()).getParameters().size()); + } + + @Test + public void testHasPath() throws Exception { + QueryStringDecoder decoder = new QueryStringDecoder("1=2", false); + Assert.assertEquals("", decoder.getPath()); + Map> params = decoder.getParameters(); + Assert.assertEquals(1, params.size()); + Assert.assertTrue(params.containsKey("1")); + List param = params.get("1"); + Assert.assertNotNull(param); + Assert.assertEquals(1, param.size()); + Assert.assertEquals("2", param.get(0)); + } @Test public void testUrlDecoding() throws Exception { diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java new file mode 100644 index 0000000000..8e98282542 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker00Test.java @@ -0,0 +1,85 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.replay; +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.DefaultChannelFuture; +import io.netty.channel.DefaultChannelPipeline; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.HttpChunkAggregator; +import io.netty.handler.codec.http.HttpHeaders.Names; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseEncoder; + +import java.nio.charset.Charset; + +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +public class WebSocketServerHandshaker00Test { + + private DefaultChannelPipeline createPipeline() { + DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); + pipeline.addLast("chunkAggregator", new HttpChunkAggregator(42)); + pipeline.addLast("wsdecoder", new HttpRequestDecoder()); + pipeline.addLast("wsencoder", new HttpResponseEncoder()); + return pipeline; + } + + @Test + public void testPerformOpeningHandshake() { + Channel channelMock = EasyMock.createMock(Channel.class); + + DefaultChannelPipeline pipeline = createPipeline(); + EasyMock.expect(channelMock.getPipeline()).andReturn(pipeline); + + // capture the http response in order to verify the headers + Capture res = new Capture(); + EasyMock.expect(channelMock.write(capture(res))).andReturn(new DefaultChannelFuture(channelMock, true)); + + replay(channelMock); + + HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat"); + req.setHeader(Names.HOST, "server.example.com"); + req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); + req.setHeader(Names.CONNECTION, "Upgrade"); + req.setHeader(Names.ORIGIN, "http://example.com"); + req.setHeader(Names.SEC_WEBSOCKET_KEY1, "4 @1 46546xW%0l 1 5"); + req.setHeader(Names.SEC_WEBSOCKET_KEY2, "12998 5 Y3 1 .P00"); + req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat"); + + ChannelBuffer buffer = ChannelBuffers.copiedBuffer("^n:ds[4U", Charset.defaultCharset()); + req.setContent(buffer); + + WebSocketServerHandshaker00 handsaker = new WebSocketServerHandshaker00("ws://example.com/chat", "chat"); + handsaker.handshake(channelMock, req); + + Assert.assertEquals("ws://example.com/chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_LOCATION)); + Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL)); + Assert.assertEquals("8jKS'y:G*Co,Wxa-", res.getValue().getContent().toString(Charset.defaultCharset())); + } +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java new file mode 100644 index 0000000000..6ca8a495d1 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker08Test.java @@ -0,0 +1,77 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.replay; +import io.netty.channel.Channel; +import io.netty.channel.DefaultChannelFuture; +import io.netty.channel.DefaultChannelPipeline; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.HttpChunkAggregator; +import io.netty.handler.codec.http.HttpHeaders.Names; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseEncoder; + +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +public class WebSocketServerHandshaker08Test { + + private DefaultChannelPipeline createPipeline() { + DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); + pipeline.addLast("chunkAggregator", new HttpChunkAggregator(42)); + pipeline.addLast("requestDecoder", new HttpRequestDecoder()); + pipeline.addLast("responseEncoder", new HttpResponseEncoder()); + return pipeline; + } + + @Test + public void testPerformOpeningHandshake() { + Channel channelMock = EasyMock.createMock(Channel.class); + + DefaultChannelPipeline pipeline = createPipeline(); + EasyMock.expect(channelMock.getPipeline()).andReturn(pipeline); + + // capture the http response in order to verify the headers + Capture res = new Capture(); + EasyMock.expect(channelMock.write(capture(res))).andReturn(new DefaultChannelFuture(channelMock, true)); + + replay(channelMock); + + HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat"); + req.setHeader(Names.HOST, "server.example.com"); + req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); + req.setHeader(Names.CONNECTION, "Upgrade"); + req.setHeader(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ=="); + req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com"); + req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat"); + req.setHeader(Names.SEC_WEBSOCKET_VERSION, "8"); + + WebSocketServerHandshaker08 handsaker = new WebSocketServerHandshaker08("ws://example.com/chat", "chat", false); + handsaker.handshake(channelMock, req); + + Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT)); + Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL)); + } +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java new file mode 100644 index 0000000000..257e484fa5 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker13Test.java @@ -0,0 +1,76 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.http.websocketx; + +import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.replay; +import io.netty.channel.Channel; +import io.netty.channel.DefaultChannelFuture; +import io.netty.channel.DefaultChannelPipeline; +import io.netty.handler.codec.http.DefaultHttpRequest; +import io.netty.handler.codec.http.HttpChunkAggregator; +import io.netty.handler.codec.http.HttpHeaders.Names; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseEncoder; + +import org.easymock.Capture; +import org.easymock.EasyMock; +import org.junit.Assert; +import org.junit.Test; + +public class WebSocketServerHandshaker13Test { + + private DefaultChannelPipeline createPipeline() { + DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); + pipeline.addLast("chunkAggregator", new HttpChunkAggregator(42)); + pipeline.addLast("requestDecoder", new HttpRequestDecoder()); + pipeline.addLast("responseEncoder", new HttpResponseEncoder()); + return pipeline; + } + + @Test + public void testPerformOpeningHandshake() { + Channel channelMock = EasyMock.createMock(Channel.class); + + DefaultChannelPipeline pipeline = createPipeline(); + EasyMock.expect(channelMock.getPipeline()).andReturn(pipeline); + + // capture the http response in order to verify the headers + Capture res = new Capture(); + EasyMock.expect(channelMock.write(capture(res))).andReturn(new DefaultChannelFuture(channelMock, true)); + + replay(channelMock); + + HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat"); + req.setHeader(Names.HOST, "server.example.com"); + req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase()); + req.setHeader(Names.CONNECTION, "Upgrade"); + req.setHeader(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ=="); + req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com"); + req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat"); + req.setHeader(Names.SEC_WEBSOCKET_VERSION, "13"); + WebSocketServerHandshaker13 handsaker = new WebSocketServerHandshaker13("ws://example.com/chat", "chat", false); + handsaker.handshake(channelMock, req); + + Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT)); + Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL)); + } +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/AbstractSocketSpdyEchoTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/AbstractSocketSpdyEchoTest.java new file mode 100644 index 0000000000..d5b2d42434 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/AbstractSocketSpdyEchoTest.java @@ -0,0 +1,267 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Random; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import io.netty.bootstrap.ClientBootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.Channels; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.util.internal.ExecutorUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public abstract class AbstractSocketSpdyEchoTest { + + private static final Random random = new Random(); + static final ChannelBuffer frames = ChannelBuffers.buffer(1160); + static final int ignoredBytes = 20; + + private static ExecutorService executor; + + static { + // SPDY UNKNOWN Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(0xFFFF); + frames.writeByte(0xFF); + frames.writeMedium(4); + frames.writeInt(random.nextInt()); + + // SPDY NOOP Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(5); + frames.writeInt(0); + + // SPDY Data Frame + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + frames.writeByte(0x01); + frames.writeMedium(1024); + for (int i = 0; i < 256; i ++) { + frames.writeInt(random.nextInt()); + } + + // SPDY SYN_STREAM Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(1); + frames.writeByte(0x03); + frames.writeMedium(12); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + frames.writeShort(0x8000); + frames.writeShort(0); + + // SPDY SYN_REPLY Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(2); + frames.writeByte(0x01); + frames.writeMedium(8); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + frames.writeInt(0); + + // SPDY RST_STREAM Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(3); + frames.writeInt(8); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + frames.writeInt(random.nextInt() | 0x01); + + // SPDY SETTINGS Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(4); + frames.writeByte(0x01); + frames.writeMedium(12); + frames.writeInt(1); + frames.writeMedium(random.nextInt()); + frames.writeByte(0x03); + frames.writeInt(random.nextInt()); + + // SPDY PING Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(6); + frames.writeInt(4); + frames.writeInt(random.nextInt()); + + // SPDY GOAWAY Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(7); + frames.writeInt(4); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + + // SPDY HEADERS Frame + frames.writeByte(0x80); + frames.writeByte(2); + frames.writeShort(8); + frames.writeInt(4); + frames.writeInt(random.nextInt() & 0x7FFFFFFF); + } + + @BeforeClass + public static void init() { + executor = Executors.newCachedThreadPool(); + } + + @AfterClass + public static void destroy() { + ExecutorUtil.terminate(executor); + } + + protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); + protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); + + @Test + public void testSpdyEcho() throws Throwable { + ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor)); + ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor)); + + EchoHandler sh = new EchoHandler(true); + EchoHandler ch = new EchoHandler(false); + + sb.getPipeline().addLast("decoder", new SpdyFrameDecoder()); + sb.getPipeline().addLast("encoder", new SpdyFrameEncoder()); + sb.getPipeline().addLast("handler", sh); + + cb.getPipeline().addLast("handler", ch); + + Channel sc = sb.bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); + + ChannelFuture ccf = cb.connect(new InetSocketAddress(InetAddress.getLocalHost(), port)); + assertTrue(ccf.awaitUninterruptibly().isSuccess()); + + Channel cc = ccf.getChannel(); + cc.write(frames); + + while (ch.counter < frames.writerIndex() - ignoredBytes) { + if (sh.exception.get() != null) { + break; + } + if (ch.exception.get() != null) { + break; + } + + try { + Thread.sleep(1); + } catch (InterruptedException e) { + // Ignore. + } + } + + sh.channel.close().awaitUninterruptibly(); + ch.channel.close().awaitUninterruptibly(); + sc.close().awaitUninterruptibly(); + + if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { + throw sh.exception.get(); + } + if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { + throw ch.exception.get(); + } + if (sh.exception.get() != null) { + throw sh.exception.get(); + } + if (ch.exception.get() != null) { + throw ch.exception.get(); + } + } + + private class EchoHandler extends SimpleChannelUpstreamHandler { + volatile Channel channel; + final AtomicReference exception = new AtomicReference(); + volatile int counter; + final boolean server; + + EchoHandler(boolean server) { + super(); + this.server = server; + } + + @Override + public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) + throws Exception { + channel = e.getChannel(); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + if (server) { + Channels.write(channel, e.getMessage(), e.getRemoteAddress()); + } else { + ChannelBuffer m = (ChannelBuffer) e.getMessage(); + byte[] actual = new byte[m.readableBytes()]; + m.getBytes(0, actual); + + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(frames.getByte(ignoredBytes + i + lastIdx), actual[i]); + } + + counter += actual.length; + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) + throws Exception { + if (exception.compareAndSet(null, e.getCause())) { + e.getChannel().close(); + } + } + } +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/NioNioSocketSpdyEchoTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/NioNioSocketSpdyEchoTest.java new file mode 100644 index 0000000000..db4b2c194e --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/NioNioSocketSpdyEchoTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.concurrent.Executor; + +import io.netty.channel.ChannelFactory; +import io.netty.channel.socket.nio.NioClientSocketChannelFactory; +import io.netty.channel.socket.nio.NioServerSocketChannelFactory; + +public class NioNioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { + + @Override + protected ChannelFactory newClientSocketChannelFactory(Executor executor) { + return new NioClientSocketChannelFactory(executor, executor); + } + + @Override + protected ChannelFactory newServerSocketChannelFactory(Executor executor) { + return new NioServerSocketChannelFactory(executor, executor); + } + +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/NioOioSocketSpdyEchoTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/NioOioSocketSpdyEchoTest.java new file mode 100644 index 0000000000..c9fa404320 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/NioOioSocketSpdyEchoTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.concurrent.Executor; + +import io.netty.channel.ChannelFactory; +import io.netty.channel.socket.nio.NioClientSocketChannelFactory; +import io.netty.channel.socket.oio.OioServerSocketChannelFactory; + +public class NioOioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { + + @Override + protected ChannelFactory newClientSocketChannelFactory(Executor executor) { + return new NioClientSocketChannelFactory(executor, executor); + } + + @Override + protected ChannelFactory newServerSocketChannelFactory(Executor executor) { + return new OioServerSocketChannelFactory(executor, executor); + } + +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/OioNioSocketSpdyEchoTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/OioNioSocketSpdyEchoTest.java new file mode 100644 index 0000000000..eea3409d42 --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/OioNioSocketSpdyEchoTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.concurrent.Executor; + +import io.netty.channel.ChannelFactory; +import io.netty.channel.socket.nio.NioServerSocketChannelFactory; +import io.netty.channel.socket.oio.OioClientSocketChannelFactory; + +public class OioNioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { + + @Override + protected ChannelFactory newClientSocketChannelFactory(Executor executor) { + return new OioClientSocketChannelFactory(executor); + } + + @Override + protected ChannelFactory newServerSocketChannelFactory(Executor executor) { + return new NioServerSocketChannelFactory(executor, executor); + } + +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/OioOioSocketSpdyEchoTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/OioOioSocketSpdyEchoTest.java new file mode 100644 index 0000000000..423d6f0ffa --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/OioOioSocketSpdyEchoTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.concurrent.Executor; + +import io.netty.channel.ChannelFactory; +import io.netty.channel.socket.oio.OioClientSocketChannelFactory; +import io.netty.channel.socket.oio.OioServerSocketChannelFactory; + +public class OioOioSocketSpdyEchoTest extends AbstractSocketSpdyEchoTest { + + @Override + protected ChannelFactory newClientSocketChannelFactory(Executor executor) { + return new OioClientSocketChannelFactory(executor); + } + + @Override + protected ChannelFactory newServerSocketChannelFactory(Executor executor) { + return new OioServerSocketChannelFactory(executor, executor); + } + +} diff --git a/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java b/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java new file mode 100644 index 0000000000..84875e9fcc --- /dev/null +++ b/codec-http/src/test/java/io/netty/handler/codec/spdy/SpdySessionHandlerTest.java @@ -0,0 +1,349 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.netty.handler.codec.spdy; + +import java.util.List; +import java.util.Map; + +import io.netty.channel.Channels; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.handler.codec.embedder.DecoderEmbedder; +import org.junit.Assert; +import org.junit.Test; + +public class SpdySessionHandlerTest { + + private static final int closeSignal = SpdyCodecUtil.SPDY_SETTINGS_MAX_ID; + private static final SpdySettingsFrame closeMessage = new DefaultSpdySettingsFrame(); + + static { + closeMessage.setValue(closeSignal, 0); + } + + private void assertHeaderBlock(SpdyHeaderBlock received, SpdyHeaderBlock expected) { + for (String name: expected.getHeaderNames()) { + List expectedValues = expected.getHeaders(name); + List receivedValues = received.getHeaders(name); + Assert.assertTrue(receivedValues.containsAll(expectedValues)); + receivedValues.removeAll(expectedValues); + Assert.assertTrue(receivedValues.isEmpty()); + received.removeHeader(name); + } + Assert.assertTrue(received.getHeaders().isEmpty()); + } + + private void assertDataFrame(Object msg, int streamID, boolean last) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdyDataFrame); + SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg; + Assert.assertTrue(spdyDataFrame.getStreamID() == streamID); + Assert.assertTrue(spdyDataFrame.isLast() == last); + } + + private void assertSynReply(Object msg, int streamID, boolean last, SpdyHeaderBlock headers) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdySynReplyFrame); + SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg; + Assert.assertTrue(spdySynReplyFrame.getStreamID() == streamID); + Assert.assertTrue(spdySynReplyFrame.isLast() == last); + assertHeaderBlock(spdySynReplyFrame, headers); + } + + private void assertRstStream(Object msg, int streamID, SpdyStreamStatus status) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdyRstStreamFrame); + SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg; + Assert.assertTrue(spdyRstStreamFrame.getStreamID() == streamID); + Assert.assertTrue(spdyRstStreamFrame.getStatus().equals(status)); + } + + private void assertPing(Object msg, int ID) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdyPingFrame); + SpdyPingFrame spdyPingFrame = (SpdyPingFrame) msg; + Assert.assertTrue(spdyPingFrame.getID() == ID); + } + + private void assertGoAway(Object msg, int lastGoodStreamID) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdyGoAwayFrame); + SpdyGoAwayFrame spdyGoAwayFrame = (SpdyGoAwayFrame) msg; + Assert.assertTrue(spdyGoAwayFrame.getLastGoodStreamID() == lastGoodStreamID); + } + + private void assertHeaders(Object msg, int streamID, SpdyHeaderBlock headers) { + Assert.assertNotNull(msg); + Assert.assertTrue(msg instanceof SpdyHeadersFrame); + SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg; + Assert.assertTrue(spdyHeadersFrame.getStreamID() == streamID); + assertHeaderBlock(spdyHeadersFrame, headers); + } + + private void testSpdySessionHandler(boolean server) { + DecoderEmbedder sessionHandler = + new DecoderEmbedder( + new SpdySessionHandler(server), new EchoHandler(closeSignal, server)); + sessionHandler.pollAll(); + + int localStreamID = server ? 1 : 2; + int remoteStreamID = server ? 2 : 1; + + SpdyPingFrame localPingFrame = new DefaultSpdyPingFrame(localStreamID); + SpdyPingFrame remotePingFrame = new DefaultSpdyPingFrame(remoteStreamID); + + SpdySynStreamFrame spdySynStreamFrame = + new DefaultSpdySynStreamFrame(localStreamID, 0, (byte) 0); + spdySynStreamFrame.setHeader("Compression", "test"); + + SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamID); + spdyDataFrame.setLast(true); + + // Check if session handler returns INVALID_STREAM if it receives + // a data frame for a Stream-ID that is not open + sessionHandler.offer(new DefaultSpdyDataFrame(localStreamID)); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.INVALID_STREAM); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler returns PROTOCOL_ERROR if it receives + // a data frame for a Stream-ID before receiving a SYN_REPLY frame + sessionHandler.offer(new DefaultSpdyDataFrame(remoteStreamID)); + assertRstStream(sessionHandler.poll(), remoteStreamID, SpdyStreamStatus.PROTOCOL_ERROR); + Assert.assertNull(sessionHandler.peek()); + remoteStreamID += 2; + + // Check if session handler returns PROTOCOL_ERROR if it receives + // multiple SYN_REPLY frames for the same active Stream-ID + sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamID)); + Assert.assertNull(sessionHandler.peek()); + sessionHandler.offer(new DefaultSpdySynReplyFrame(remoteStreamID)); + assertRstStream(sessionHandler.poll(), remoteStreamID, SpdyStreamStatus.PROTOCOL_ERROR); + Assert.assertNull(sessionHandler.peek()); + remoteStreamID += 2; + + // Check if frame codec correctly compresses/uncompresses headers + sessionHandler.offer(spdySynStreamFrame); + assertSynReply(sessionHandler.poll(), localStreamID, false, spdySynStreamFrame); + Assert.assertNull(sessionHandler.peek()); + SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(localStreamID); + spdyHeadersFrame.addHeader("HEADER","test1"); + spdyHeadersFrame.addHeader("HEADER","test2"); + sessionHandler.offer(spdyHeadersFrame); + assertHeaders(sessionHandler.poll(), localStreamID, spdyHeadersFrame); + Assert.assertNull(sessionHandler.peek()); + localStreamID += 2; + + // Check if session handler closed the streams using the number + // of concurrent streams and that it returns REFUSED_STREAM + // if it receives a SYN_STREAM frame it does not wish to accept + spdySynStreamFrame.setStreamID(localStreamID); + spdySynStreamFrame.setLast(true); + spdySynStreamFrame.setUnidirectional(true); + sessionHandler.offer(spdySynStreamFrame); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.REFUSED_STREAM); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler drops active streams if it receives + // a RST_STREAM frame for that Stream-ID + sessionHandler.offer(new DefaultSpdyRstStreamFrame(remoteStreamID, 3)); + Assert.assertNull(sessionHandler.peek()); + remoteStreamID += 2; + + // Check if session handler honors UNIDIRECTIONAL streams + spdySynStreamFrame.setLast(false); + sessionHandler.offer(spdySynStreamFrame); + Assert.assertNull(sessionHandler.peek()); + spdySynStreamFrame.setUnidirectional(false); + + // Check if session handler returns PROTOCOL_ERROR if it receives + // multiple SYN_STREAM frames for the same active Stream-ID + sessionHandler.offer(spdySynStreamFrame); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.PROTOCOL_ERROR); + Assert.assertNull(sessionHandler.peek()); + localStreamID += 2; + + // Check if session handler returns PROTOCOL_ERROR if it receives + // a SYN_STREAM frame with an invalid Stream-ID + spdySynStreamFrame.setStreamID(localStreamID - 1); + sessionHandler.offer(spdySynStreamFrame); + assertRstStream(sessionHandler.poll(), localStreamID - 1, SpdyStreamStatus.PROTOCOL_ERROR); + Assert.assertNull(sessionHandler.peek()); + spdySynStreamFrame.setStreamID(localStreamID); + + // Check if session handler correctly limits the number of + // concurrent streams in the SETTINGS frame + SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame(); + spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 2); + sessionHandler.offer(spdySettingsFrame); + Assert.assertNull(sessionHandler.peek()); + sessionHandler.offer(spdySynStreamFrame); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.REFUSED_STREAM); + Assert.assertNull(sessionHandler.peek()); + spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 4); + sessionHandler.offer(spdySettingsFrame); + Assert.assertNull(sessionHandler.peek()); + sessionHandler.offer(spdySynStreamFrame); + assertSynReply(sessionHandler.poll(), localStreamID, false, spdySynStreamFrame); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler rejects HEADERS for closed streams + int testStreamID = spdyDataFrame.getStreamID(); + sessionHandler.offer(spdyDataFrame); + assertDataFrame(sessionHandler.poll(), testStreamID, spdyDataFrame.isLast()); + Assert.assertNull(sessionHandler.peek()); + spdyHeadersFrame.setStreamID(testStreamID); + sessionHandler.offer(spdyHeadersFrame); + assertRstStream(sessionHandler.poll(), testStreamID, SpdyStreamStatus.INVALID_STREAM); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler returns PROTOCOL_ERROR if it receives + // an invalid HEADERS frame + spdyHeadersFrame.setStreamID(localStreamID); + spdyHeadersFrame.setInvalid(); + sessionHandler.offer(spdyHeadersFrame); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.PROTOCOL_ERROR); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler returns identical local PINGs + sessionHandler.offer(localPingFrame); + assertPing(sessionHandler.poll(), localPingFrame.getID()); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler ignores un-initiated remote PINGs + sessionHandler.offer(remotePingFrame); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler sends a GOAWAY frame when closing + sessionHandler.offer(closeMessage); + assertGoAway(sessionHandler.poll(), localStreamID); + Assert.assertNull(sessionHandler.peek()); + localStreamID += 2; + + // Check if session handler returns REFUSED_STREAM if it receives + // SYN_STREAM frames after sending a GOAWAY frame + spdySynStreamFrame.setStreamID(localStreamID); + sessionHandler.offer(spdySynStreamFrame); + assertRstStream(sessionHandler.poll(), localStreamID, SpdyStreamStatus.REFUSED_STREAM); + Assert.assertNull(sessionHandler.peek()); + + // Check if session handler ignores Data frames after sending + // a GOAWAY frame + spdyDataFrame.setStreamID(localStreamID); + sessionHandler.offer(spdyDataFrame); + Assert.assertNull(sessionHandler.peek()); + + sessionHandler.finish(); + } + + @Test + public void testSpdyClientSessionHandler() { + testSpdySessionHandler(false); + } + + @Test + public void testSpdyServerSessionHandler() { + testSpdySessionHandler(true); + } + + // Echo Handler opens 4 half-closed streams on session connection + // and then sets the number of concurrent streams to 3 + private class EchoHandler extends SimpleChannelUpstreamHandler { + private int closeSignal; + private boolean server; + + EchoHandler(int closeSignal, boolean server) { + super(); + this.closeSignal = closeSignal; + this.server = server; + } + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) + throws Exception { + + // Initiate 4 new streams + int streamID = server ? 2 : 1; + SpdySynStreamFrame spdySynStreamFrame = + new DefaultSpdySynStreamFrame(streamID, 0, (byte) 0); + spdySynStreamFrame.setLast(true); + Channels.write(e.getChannel(), spdySynStreamFrame); + spdySynStreamFrame.setStreamID(spdySynStreamFrame.getStreamID() + 2); + Channels.write(e.getChannel(), spdySynStreamFrame); + spdySynStreamFrame.setStreamID(spdySynStreamFrame.getStreamID() + 2); + Channels.write(e.getChannel(), spdySynStreamFrame); + spdySynStreamFrame.setStreamID(spdySynStreamFrame.getStreamID() + 2); + Channels.write(e.getChannel(), spdySynStreamFrame); + + // Limit the number of concurrent streams to 3 + SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame(); + spdySettingsFrame.setValue(SpdySettingsFrame.SETTINGS_MAX_CONCURRENT_STREAMS, 3); + Channels.write(e.getChannel(), spdySettingsFrame); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + Object msg = e.getMessage(); + if ((msg instanceof SpdyDataFrame) || + (msg instanceof SpdyPingFrame) || + (msg instanceof SpdyHeadersFrame)) { + + Channels.write(e.getChannel(), msg, e.getRemoteAddress()); + return; + } + + if (msg instanceof SpdySynStreamFrame) { + + SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg; + + int streamID = spdySynStreamFrame.getStreamID(); + SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID); + spdySynReplyFrame.setLast(spdySynStreamFrame.isLast()); + for (Map.Entry entry: spdySynStreamFrame.getHeaders()) { + spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue()); + } + + Channels.write(e.getChannel(), spdySynReplyFrame, e.getRemoteAddress()); + return; + } + + if (msg instanceof SpdySettingsFrame) { + + SpdySettingsFrame spdySettingsFrame = (SpdySettingsFrame) msg; + if (spdySettingsFrame.isSet(closeSignal)) { + Channels.close(e.getChannel()); + } + } + } + } +} diff --git a/codec/pom.xml b/codec/pom.xml new file mode 100644 index 0000000000..a8691be22c --- /dev/null +++ b/codec/pom.xml @@ -0,0 +1,45 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-codec + jar + + Netty/Codec + + + + ${project.groupId} + netty-transport + ${project.version} + + + com.google.protobuf + protobuf-java + true + + + + diff --git a/src/main/java/io/netty/handler/codec/base64/Base64.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64.java similarity index 96% rename from src/main/java/io/netty/handler/codec/base64/Base64.java rename to codec/src/main/java/io/netty/handler/codec/base64/Base64.java index 64339345ee..f6d01c99da 100644 --- a/src/main/java/io/netty/handler/codec/base64/Base64.java +++ b/codec/src/main/java/io/netty/handler/codec/base64/Base64.java @@ -32,7 +32,7 @@ import io.netty.buffer.HeapChannelBufferFactory; * @apiviz.landmark * @apiviz.uses io.netty.handler.codec.base64.Base64Dialect */ -public class Base64 { +public final class Base64 { /** Maximum line length (76) of Base64 output. */ private static final int MAX_LINE_LENGTH = 76; @@ -207,7 +207,7 @@ public class Base64 { // We have to shift left 24 in order to flush out the 1's that appear // when Java treats a value as negative that is cast from a byte to an int. int inBuff = - (numSigBytes > 0? src.getByte(srcOffset ) << 24 >>> 8 : 0) | + (numSigBytes > 0? src.getByte(srcOffset) << 24 >>> 8 : 0) | (numSigBytes > 1? src.getByte(srcOffset + 1) << 24 >>> 16 : 0) | (numSigBytes > 2? src.getByte(srcOffset + 2) << 24 >>> 24 : 0); @@ -301,9 +301,9 @@ public class Base64 { sbiDecode = DECODABET[sbiCrop]; if (sbiDecode >= WHITE_SPACE_ENC) { // White space, Equals sign or better - if (sbiDecode >= EQUALS_SIGN_ENC) { + if (sbiDecode >= EQUALS_SIGN_ENC) { // Equals sign or better b4[b4Posn ++] = sbiCrop; - if (b4Posn > 3) { + if (b4Posn > 3) { // Quartet built outBuffPosn += decode4to3( b4, 0, dest, outBuffPosn, dialect); b4Posn = 0; @@ -312,10 +312,9 @@ public class Base64 { if (sbiCrop == EQUALS_SIGN) { break; } - } // end if: quartet built - } // end if: equals sign or better - } // end if: white space, equals sign or better - else { + } + } + } else { throw new IllegalArgumentException( "bad Base64 input character at " + i + ": " + src.getUnsignedByte(i) + " (decimal)"); @@ -331,18 +330,16 @@ public class Base64 { byte[] DECODABET = decodabet(dialect); - // Example: Dk== if (src[srcOffset + 2] == EQUALS_SIGN) { + // Example: Dk== int outBuff = (DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12; dest.setByte(destOffset, (byte) (outBuff >>> 16)); return 1; - } - - // Example: DkL= - else if (src[srcOffset + 3] == EQUALS_SIGN) { + } else if (src[srcOffset + 3] == EQUALS_SIGN) { + // Example: DkL= int outBuff = (DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12 | @@ -351,10 +348,8 @@ public class Base64 { dest.setByte(destOffset , (byte) (outBuff >>> 16)); dest.setByte(destOffset + 1, (byte) (outBuff >>> 8)); return 2; - } - - // Example: DkLE - else { + } else { + // Example: DkLE int outBuff; try { outBuff = diff --git a/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/base64/Base64Decoder.java rename to codec/src/main/java/io/netty/handler/codec/base64/Base64Decoder.java diff --git a/src/main/java/io/netty/handler/codec/base64/Base64Dialect.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Dialect.java similarity index 100% rename from src/main/java/io/netty/handler/codec/base64/Base64Dialect.java rename to codec/src/main/java/io/netty/handler/codec/base64/Base64Dialect.java diff --git a/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java b/codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/base64/Base64Encoder.java rename to codec/src/main/java/io/netty/handler/codec/base64/Base64Encoder.java diff --git a/src/main/java/io/netty/handler/codec/base64/package-info.java b/codec/src/main/java/io/netty/handler/codec/base64/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/base64/package-info.java rename to codec/src/main/java/io/netty/handler/codec/base64/package-info.java diff --git a/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java similarity index 98% rename from src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java rename to codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java index bfd305297f..c8ef66f2c4 100644 --- a/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayDecoder.java @@ -56,7 +56,7 @@ public class ByteArrayDecoder extends OneToOneDecoder { if (!(msg instanceof ChannelBuffer)) { return msg; } - ChannelBuffer buf = (ChannelBuffer )msg; + ChannelBuffer buf = (ChannelBuffer) msg; byte[] array; if (buf.hasArray()) { if (buf.arrayOffset() == 0 && buf.readableBytes() == buf.capacity()) { diff --git a/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java b/codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java rename to codec/src/main/java/io/netty/handler/codec/bytes/ByteArrayEncoder.java diff --git a/src/main/java/io/netty/handler/codec/bytes/package-info.java b/codec/src/main/java/io/netty/handler/codec/bytes/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/bytes/package-info.java rename to codec/src/main/java/io/netty/handler/codec/bytes/package-info.java diff --git a/src/main/java/io/netty/handler/codec/compression/CompressionException.java b/codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java similarity index 100% rename from src/main/java/io/netty/handler/codec/compression/CompressionException.java rename to codec/src/main/java/io/netty/handler/codec/compression/CompressionException.java diff --git a/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java similarity index 89% rename from src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java rename to codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java index 1c89d42436..7904ef5b60 100644 --- a/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/ZlibDecoder.java @@ -32,6 +32,7 @@ import io.netty.util.internal.jzlib.ZStream; public class ZlibDecoder extends OneToOneDecoder { private final ZStream z = new ZStream(); + private byte[] dictionary; private volatile boolean finished; /** @@ -72,17 +73,13 @@ public class ZlibDecoder extends OneToOneDecoder { if (dictionary == null) { throw new NullPointerException("dictionary"); } + this.dictionary = dictionary; synchronized (z) { int resultCode; resultCode = z.inflateInit(JZlib.W_ZLIB); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); - } else { - resultCode = z.inflateSetDictionary(dictionary, dictionary.length); - if (resultCode != JZlib.Z_OK) { - ZlibUtil.fail(z, "failed to set the dictionary", resultCode); - } } } } @@ -131,6 +128,16 @@ public class ZlibDecoder extends OneToOneDecoder { z.next_out_index = 0; switch (resultCode) { + case JZlib.Z_NEED_DICT: + if (dictionary == null) { + ZlibUtil.fail(z, "decompression failure", resultCode); + } else { + resultCode = z.inflateSetDictionary(dictionary, dictionary.length); + if (resultCode != JZlib.Z_OK) { + ZlibUtil.fail(z, "failed to set the dictionary", resultCode); + } + } + break; case JZlib.Z_STREAM_END: finished = true; // Do not decode anymore. z.inflateEnd(); diff --git a/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java similarity index 72% rename from src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java rename to codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java index 960269536a..77e9c0ebb0 100644 --- a/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/ZlibEncoder.java @@ -46,7 +46,8 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne private volatile ChannelHandlerContext ctx; /** - * Creates a new zlib encoder with the default compression level ({@code 6}) + * Creates a new zlib encoder with the default compression level ({@code 6}), + * default window bits ({@code 15}), default memory level ({@code 8}), * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @throws CompressionException if failed to initialize zlib @@ -56,7 +57,8 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } /** - * Creates a new zlib encoder with the specified {@code compressionLevel} + * Creates a new zlib encoder with the specified {@code compressionLevel}, + * default window bits ({@code 15}), default memory level ({@code 8}), * and the default wrapper ({@link ZlibWrapper#ZLIB}). * * @param compressionLevel @@ -71,7 +73,8 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } /** - * Creates a new zlib encoder with the default compression level ({@code 6}) + * Creates a new zlib encoder with the default compression level ({@code 6}), + * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified wrapper. * * @throws CompressionException if failed to initialize zlib @@ -81,8 +84,10 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } /** - * Creates a new zlib encoder with the specified {@code compressionLevel} + * Creates a new zlib encoder with the specified {@code compressionLevel}, + * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified wrapper. + * * @param compressionLevel * {@code 1} yields the fastest compression and {@code 9} yields the * best compression. {@code 0} means no compression. The default @@ -91,11 +96,46 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(ZlibWrapper wrapper, int compressionLevel) { + this(wrapper, compressionLevel, 15, 8); + } + + /** + * Creates a new zlib encoder with the specified {@code compressionLevel}, + * the specified {@code windowBits}, the specified {@code memLevel}, and + * the specified wrapper. + * + * @param compressionLevel + * {@code 1} yields the fastest compression and {@code 9} yields the + * best compression. {@code 0} means no compression. The default + * compression level is {@code 6}. + * @param windowBits + * The base two logarithm of the size of the history buffer. The + * value should be in the range {@code 9} to {@code 15} inclusive. + * Larger values result in better compression at the expense of + * memory usage. The default value is {@code 15}. + * @param memLevel + * How much memory should be allocated for the internal compression + * state. {@code 1} uses minimum memory and {@code 9} uses maximum + * memory. Larger values result in better and faster compression + * at the expense of memory usage. The default value is {@code 8} + * + * @throws CompressionException if failed to initialize zlib + */ + public ZlibEncoder(ZlibWrapper wrapper, int compressionLevel, int windowBits, int memLevel) { + if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException( "compressionLevel: " + compressionLevel + " (expected: 0-9)"); } + if (windowBits < 9 || windowBits > 15) { + throw new IllegalArgumentException( + "windowBits: " + windowBits + " (expected: 9-15)"); + } + if (memLevel < 1 || memLevel > 9) { + throw new IllegalArgumentException( + "memLevel: " + memLevel + " (expected: 1-9)"); + } if (wrapper == null) { throw new NullPointerException("wrapper"); } @@ -106,7 +146,9 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } synchronized (z) { - int resultCode = z.deflateInit(compressionLevel, ZlibUtil.convertWrapperType(wrapper)); + int resultCode = z.deflateInit( + compressionLevel, windowBits, memLevel, + ZlibUtil.convertWrapperType(wrapper)); if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } @@ -114,7 +156,8 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } /** - * Creates a new zlib encoder with the default compression level ({@code 6}) + * Creates a new zlib encoder with the default compression level ({@code 6}), + * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. @@ -128,7 +171,8 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne } /** - * Creates a new zlib encoder with the specified {@code compressionLevel} + * Creates a new zlib encoder with the specified {@code compressionLevel}, + * default window bits ({@code 15}), default memory level ({@code 8}), * and the specified preset dictionary. The wrapper is always * {@link ZlibWrapper#ZLIB} because it is the only format that supports * the preset dictionary. @@ -142,22 +186,60 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne * @throws CompressionException if failed to initialize zlib */ public ZlibEncoder(int compressionLevel, byte[] dictionary) { + this(compressionLevel, 15, 8, dictionary); + } + + /** + * Creates a new zlib encoder with the specified {@code compressionLevel}, + * the specified {@code windowBits}, the specified {@code memLevel}, + * and the specified preset dictionary. The wrapper is always + * {@link ZlibWrapper#ZLIB} because it is the only format that supports + * the preset dictionary. + * + * @param compressionLevel + * {@code 1} yields the fastest compression and {@code 9} yields the + * best compression. {@code 0} means no compression. The default + * compression level is {@code 6}. + * @param windowBits + * The base two logarithm of the size of the history buffer. The + * value should be in the range {@code 9} to {@code 15} inclusive. + * Larger values result in better compression at the expense of + * memory usage. The default value is {@code 15}. + * @param memLevel + * How much memory should be allocated for the internal compression + * state. {@code 1} uses minimum memory and {@code 9} uses maximum + * memory. Larger values result in better and faster compression + * at the expense of memory usage. The default value is {@code 8} + * @param dictionary the preset dictionary + * + * @throws CompressionException if failed to initialize zlib + */ + public ZlibEncoder(int compressionLevel, int windowBits, int memLevel, byte[] dictionary) { if (compressionLevel < 0 || compressionLevel > 9) { throw new IllegalArgumentException("compressionLevel: " + compressionLevel + " (expected: 0-9)"); } - + if (windowBits < 9 || windowBits > 15) { + throw new IllegalArgumentException( + "windowBits: " + windowBits + " (expected: 9-15)"); + } + if (memLevel < 1 || memLevel > 9) { + throw new IllegalArgumentException( + "memLevel: " + memLevel + " (expected: 1-9)"); + } if (dictionary == null) { throw new NullPointerException("dictionary"); } synchronized (z) { int resultCode; - resultCode = z.deflateInit(compressionLevel, JZlib.W_ZLIB); // Default: ZLIB format + resultCode = z.deflateInit( + compressionLevel, windowBits, memLevel, + JZlib.W_ZLIB); // Default: ZLIB format if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "initialization failure", resultCode); } else { resultCode = z.deflateSetDictionary(dictionary, dictionary.length); - if (resultCode != JZlib.Z_OK){ + if (resultCode != JZlib.Z_OK) { ZlibUtil.fail(z, "failed to set the dictionary", resultCode); } } diff --git a/src/main/java/io/netty/handler/codec/compression/ZlibUtil.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibUtil.java similarity index 100% rename from src/main/java/io/netty/handler/codec/compression/ZlibUtil.java rename to codec/src/main/java/io/netty/handler/codec/compression/ZlibUtil.java diff --git a/src/main/java/io/netty/handler/codec/compression/ZlibWrapper.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibWrapper.java similarity index 100% rename from src/main/java/io/netty/handler/codec/compression/ZlibWrapper.java rename to codec/src/main/java/io/netty/handler/codec/compression/ZlibWrapper.java diff --git a/src/main/java/io/netty/handler/codec/compression/package-info.java b/codec/src/main/java/io/netty/handler/codec/compression/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/compression/package-info.java rename to codec/src/main/java/io/netty/handler/codec/compression/package-info.java diff --git a/src/main/java/io/netty/handler/codec/embedder/AbstractCodecEmbedder.java b/codec/src/main/java/io/netty/handler/codec/embedder/AbstractCodecEmbedder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/AbstractCodecEmbedder.java rename to codec/src/main/java/io/netty/handler/codec/embedder/AbstractCodecEmbedder.java diff --git a/src/main/java/io/netty/handler/codec/embedder/CodecEmbedder.java b/codec/src/main/java/io/netty/handler/codec/embedder/CodecEmbedder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/CodecEmbedder.java rename to codec/src/main/java/io/netty/handler/codec/embedder/CodecEmbedder.java diff --git a/src/main/java/io/netty/handler/codec/embedder/CodecEmbedderException.java b/codec/src/main/java/io/netty/handler/codec/embedder/CodecEmbedderException.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/CodecEmbedderException.java rename to codec/src/main/java/io/netty/handler/codec/embedder/CodecEmbedderException.java diff --git a/src/main/java/io/netty/handler/codec/embedder/DecoderEmbedder.java b/codec/src/main/java/io/netty/handler/codec/embedder/DecoderEmbedder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/DecoderEmbedder.java rename to codec/src/main/java/io/netty/handler/codec/embedder/DecoderEmbedder.java diff --git a/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannel.java b/codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannel.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/EmbeddedChannel.java rename to codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannel.java diff --git a/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java b/codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java similarity index 94% rename from src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java rename to codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java index c2bd56bbf9..c7a8e197fb 100644 --- a/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java +++ b/codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedChannelFactory.java @@ -21,7 +21,7 @@ import io.netty.channel.ChannelPipeline; /** */ -class EmbeddedChannelFactory implements ChannelFactory { +final class EmbeddedChannelFactory implements ChannelFactory { static final ChannelFactory INSTANCE = new EmbeddedChannelFactory(); diff --git a/src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java b/codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java similarity index 99% rename from src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java rename to codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java index 0147ba5b47..2ae835b9b3 100644 --- a/src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java +++ b/codec/src/main/java/io/netty/handler/codec/embedder/EmbeddedSocketAddress.java @@ -17,8 +17,6 @@ package io.netty.handler.codec.embedder; import java.net.SocketAddress; -/** - */ class EmbeddedSocketAddress extends SocketAddress { private static final long serialVersionUID = 1400788804624980619L; } diff --git a/src/main/java/io/netty/handler/codec/embedder/EncoderEmbedder.java b/codec/src/main/java/io/netty/handler/codec/embedder/EncoderEmbedder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/EncoderEmbedder.java rename to codec/src/main/java/io/netty/handler/codec/embedder/EncoderEmbedder.java diff --git a/src/main/java/io/netty/handler/codec/embedder/package-info.java b/codec/src/main/java/io/netty/handler/codec/embedder/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/codec/embedder/package-info.java rename to codec/src/main/java/io/netty/handler/codec/embedder/package-info.java diff --git a/src/main/java/io/netty/handler/codec/frame/CorruptedFrameException.java b/codec/src/main/java/io/netty/handler/codec/frame/CorruptedFrameException.java similarity index 100% rename from src/main/java/io/netty/handler/codec/frame/CorruptedFrameException.java rename to codec/src/main/java/io/netty/handler/codec/frame/CorruptedFrameException.java diff --git a/src/main/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoder.java similarity index 100% rename from src/main/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoder.java rename to codec/src/main/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoder.java diff --git a/src/main/java/io/netty/handler/codec/frame/Delimiters.java b/codec/src/main/java/io/netty/handler/codec/frame/Delimiters.java similarity index 98% rename from src/main/java/io/netty/handler/codec/frame/Delimiters.java rename to codec/src/main/java/io/netty/handler/codec/frame/Delimiters.java index e00a059940..8ffc2a5255 100644 --- a/src/main/java/io/netty/handler/codec/frame/Delimiters.java +++ b/codec/src/main/java/io/netty/handler/codec/frame/Delimiters.java @@ -21,7 +21,7 @@ import io.netty.buffer.ChannelBuffers; /** * A set of commonly used delimiters for {@link DelimiterBasedFrameDecoder}. */ -public class Delimiters { +public final class Delimiters { /** * Returns a {@code NUL (0x00)} delimiter, which could be used for diff --git a/src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java similarity index 71% rename from src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java rename to codec/src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java index d36519925c..21537efced 100644 --- a/src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/frame/FixedLengthFrameDecoder.java @@ -16,6 +16,7 @@ package io.netty.handler.codec.frame; import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; @@ -38,20 +39,30 @@ import io.netty.channel.ChannelHandlerContext; public class FixedLengthFrameDecoder extends FrameDecoder { private final int frameLength; + private final boolean allocateFullBuffer; + + /** + * Calls {@link #FixedLengthFrameDecoder(int, boolean)} with false + */ + public FixedLengthFrameDecoder(int frameLength) { + this(frameLength, false); + } /** * Creates a new instance. * * @param frameLength the length of the frame + * @param allocateFullBuffer true if the cumulative {@link ChannelBuffer} should use the {@link #frameLength} as its initial size */ - public FixedLengthFrameDecoder(int frameLength) { + public FixedLengthFrameDecoder(int frameLength, boolean allocateFullBuffer) { if (frameLength <= 0) { throw new IllegalArgumentException( "frameLength must be a positive integer: " + frameLength); } this.frameLength = frameLength; + this.allocateFullBuffer = allocateFullBuffer; } - + @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { @@ -61,4 +72,13 @@ public class FixedLengthFrameDecoder extends FrameDecoder { return buffer.readBytes(frameLength); } } + + @Override + protected ChannelBuffer createCumulationDynamicBuffer(ChannelHandlerContext ctx) { + if (allocateFullBuffer) { + return ChannelBuffers.dynamicBuffer(frameLength, ctx.getChannel().getConfig().getBufferFactory()); + } + return super.createCumulationDynamicBuffer(ctx); + } + } diff --git a/src/main/java/io/netty/handler/codec/frame/FrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/frame/FrameDecoder.java similarity index 95% rename from src/main/java/io/netty/handler/codec/frame/FrameDecoder.java rename to codec/src/main/java/io/netty/handler/codec/frame/FrameDecoder.java index ee5e87dfbd..73c797191b 100644 --- a/src/main/java/io/netty/handler/codec/frame/FrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/frame/FrameDecoder.java @@ -358,15 +358,25 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler { * Get the currently used {@link ChannelBuffer} for cumulation or create one in a lazy fashion if none exist yet * * @param ctx the {@link ChannelHandlerContext} for this handler - * @return buffer the {@link ChannelBuffer} which is used fo cumulation + * @return buffer the {@link ChannelBuffer} which is used for cumulation */ private ChannelBuffer cumulation(ChannelHandlerContext ctx) { ChannelBuffer c = cumulation; if (c == null) { - c = ChannelBuffers.dynamicBuffer( - ctx.getChannel().getConfig().getBufferFactory()); + c = createCumulationDynamicBuffer(ctx); cumulation = c; } return c; } + + /** + * Create a new {@link ChannelBuffer} which is used for the cumulation. Be aware that this MUST be a dynamic buffer. Sub-classes may override this to provide a + * dynamic {@link ChannelBuffer} which has some prelocated size that better fit their need. + * + * @param ctx {@link ChannelHandlerContext} for this handler + * @return buffer the {@link ChannelBuffer} which is used for cumulation + */ + protected ChannelBuffer createCumulationDynamicBuffer(ChannelHandlerContext ctx) { + return ChannelBuffers.dynamicBuffer(ctx.getChannel().getConfig().getBufferFactory()); + } } diff --git a/src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java similarity index 98% rename from src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java rename to codec/src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java index 33d95675d9..a935f89605 100644 --- a/src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoder.java @@ -145,8 +145,8 @@ import io.netty.handler.codec.serialization.ObjectDecoder; * header from the frame. If you don't want to strip the prepended header, you * could specify 0 for initialBytesToSkip. *
- * lengthFieldOffset   = 1 (= the length of HDR1)
- * lengthFieldLength   = 2
+ * lengthFieldOffset   = 1 (= the length of HDR1)
+ * lengthFieldLength   = 2
  * lengthAdjustment    = 1 (= the length of HDR2)
  * initialBytesToStrip = 3 (= the length of HDR1 + LEN)
  *
@@ -205,7 +205,7 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
      *        the offset of the length field
      * @param lengthFieldLength
      *        the length of the length field
- */
+     */
     public LengthFieldBasedFrameDecoder(
             int maxFrameLength,
             int lengthFieldOffset, int lengthFieldLength) {
@@ -403,14 +403,12 @@ public class LengthFieldBasedFrameDecoder extends FrameDecoder {
             this.tooLongFrameLength = 0;
             discardingTooLongFrame = false;
             if ((!failFast) ||
-                (failFast && firstDetectionOfTooLongFrame))
-            {
+                (failFast && firstDetectionOfTooLongFrame)) {
                 fail(ctx, tooLongFrameLength);
             }
         } else {
             // Keep discarding and notify handlers if necessary.
-            if (failFast && firstDetectionOfTooLongFrame)
-            {
+            if (failFast && firstDetectionOfTooLongFrame) {
                 fail(ctx, this.tooLongFrameLength);
             }
         }
diff --git a/src/main/java/io/netty/handler/codec/frame/LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/frame/LengthFieldPrepender.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/frame/LengthFieldPrepender.java
rename to codec/src/main/java/io/netty/handler/codec/frame/LengthFieldPrepender.java
diff --git a/src/main/java/io/netty/handler/codec/frame/TooLongFrameException.java b/codec/src/main/java/io/netty/handler/codec/frame/TooLongFrameException.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/frame/TooLongFrameException.java
rename to codec/src/main/java/io/netty/handler/codec/frame/TooLongFrameException.java
diff --git a/src/main/java/io/netty/handler/codec/frame/package-info.java b/codec/src/main/java/io/netty/handler/codec/frame/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/frame/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/frame/package-info.java
diff --git a/src/main/java/io/netty/handler/codec/oneone/OneToOneDecoder.java b/codec/src/main/java/io/netty/handler/codec/oneone/OneToOneDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/oneone/OneToOneDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/oneone/OneToOneDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/oneone/OneToOneEncoder.java b/codec/src/main/java/io/netty/handler/codec/oneone/OneToOneEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/oneone/OneToOneEncoder.java
rename to codec/src/main/java/io/netty/handler/codec/oneone/OneToOneEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/oneone/package-info.java b/codec/src/main/java/io/netty/handler/codec/oneone/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/oneone/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/oneone/package-info.java
diff --git a/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java
index 2aadf3552b..e15c13fa6c 100644
--- a/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java
+++ b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufDecoder.java
@@ -94,7 +94,7 @@ public class ProtobufDecoder extends OneToOneDecoder {
         ChannelBuffer buf = (ChannelBuffer) msg;
         if (buf.hasArray()) {
             final int offset = buf.readerIndex();
-            if(extensionRegistry == null) {
+            if (extensionRegistry == null) {
                 return prototype.newBuilderForType().mergeFrom(
                         buf.array(), buf.arrayOffset() + offset, buf.readableBytes()).build();
             } else {
diff --git a/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java
rename to codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java
rename to codec/src/main/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrepender.java
diff --git a/src/main/java/io/netty/handler/codec/protobuf/package-info.java b/codec/src/main/java/io/netty/handler/codec/protobuf/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/protobuf/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/protobuf/package-info.java
diff --git a/src/main/java/io/netty/handler/codec/replay/ReplayError.java b/codec/src/main/java/io/netty/handler/codec/replay/ReplayError.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/replay/ReplayError.java
rename to codec/src/main/java/io/netty/handler/codec/replay/ReplayError.java
index a2d98abfee..42aabe8548 100644
--- a/src/main/java/io/netty/handler/codec/replay/ReplayError.java
+++ b/codec/src/main/java/io/netty/handler/codec/replay/ReplayError.java
@@ -16,8 +16,6 @@
 package io.netty.handler.codec.replay;
 
 
-/**
- */
 class ReplayError extends Error {
 
     private static final long serialVersionUID = 2666698631187527681L;
diff --git a/src/main/java/io/netty/handler/codec/replay/ReplayingDecoder.java b/codec/src/main/java/io/netty/handler/codec/replay/ReplayingDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/replay/ReplayingDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/replay/ReplayingDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java b/codec/src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java
rename to codec/src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java
index 1a28dfa8f1..b258af7185 100644
--- a/src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java
+++ b/codec/src/main/java/io/netty/handler/codec/replay/ReplayingDecoderBuffer.java
@@ -29,8 +29,6 @@ import io.netty.buffer.ChannelBufferFactory;
 import io.netty.buffer.ChannelBufferIndexFinder;
 import io.netty.buffer.ChannelBuffers;
 
-/**
- */
 class ReplayingDecoderBuffer implements ChannelBuffer {
 
     private static final Error REPLAY = new ReplayError();
diff --git a/src/main/java/io/netty/handler/codec/replay/UnreplayableOperationException.java b/codec/src/main/java/io/netty/handler/codec/replay/UnreplayableOperationException.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/replay/UnreplayableOperationException.java
rename to codec/src/main/java/io/netty/handler/codec/replay/UnreplayableOperationException.java
diff --git a/src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java b/codec/src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java
rename to codec/src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java
index 820fe0f187..57b5be4fc7 100644
--- a/src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java
+++ b/codec/src/main/java/io/netty/handler/codec/replay/UnsafeDynamicChannelBuffer.java
@@ -18,8 +18,6 @@ package io.netty.handler.codec.replay;
 import io.netty.buffer.ChannelBufferFactory;
 import io.netty.buffer.DynamicChannelBuffer;
 
-/**
- */
 class UnsafeDynamicChannelBuffer extends DynamicChannelBuffer {
 
     UnsafeDynamicChannelBuffer(ChannelBufferFactory factory) {
diff --git a/src/main/java/io/netty/handler/codec/replay/VoidEnum.java b/codec/src/main/java/io/netty/handler/codec/replay/VoidEnum.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/replay/VoidEnum.java
rename to codec/src/main/java/io/netty/handler/codec/replay/VoidEnum.java
diff --git a/src/main/java/io/netty/handler/codec/replay/package-info.java b/codec/src/main/java/io/netty/handler/codec/replay/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/replay/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/replay/package-info.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/CachingClassResolver.java b/codec/src/main/java/io/netty/handler/codec/serialization/CachingClassResolver.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/CachingClassResolver.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CachingClassResolver.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ClassLoaderClassResolver.java b/codec/src/main/java/io/netty/handler/codec/serialization/ClassLoaderClassResolver.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/ClassLoaderClassResolver.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ClassLoaderClassResolver.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ClassResolver.java b/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolver.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/ClassResolver.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ClassResolver.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java b/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java
index c6c756e94f..edf1ab608c 100644
--- a/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/ClassResolvers.java
@@ -19,7 +19,7 @@ import java.lang.ref.Reference;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
 
-public class ClassResolvers {
+public final class ClassResolvers {
 
     /**
      * cache disabled
@@ -86,4 +86,8 @@ public class ClassResolvers {
 
         return ClassResolvers.class.getClassLoader();
     }
+
+    private ClassResolvers() {
+        // Unused
+    }
 }
diff --git a/src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java b/codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java
similarity index 97%
rename from src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java
index baa9f16be1..9e7e766b38 100644
--- a/src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectInputStream.java
@@ -22,8 +22,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
 import java.io.StreamCorruptedException;
 
-/**
- */
 class CompactObjectInputStream extends ObjectInputStream {
     
     private final ClassResolver classResolver;
@@ -55,7 +53,7 @@ class CompactObjectInputStream extends ObjectInputStream {
         case CompactObjectOutputStream.TYPE_THIN_DESCRIPTOR:
             String className = readUTF();
             Class clazz = classResolver.resolve(className);
-            return ObjectStreamClass.lookupAny(clazz);
+            return ObjectStreamClass.lookup(clazz);
         default:
             throw new StreamCorruptedException(
                     "Unexpected class descriptor type: " + type);
diff --git a/src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java b/codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java
similarity index 94%
rename from src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java
index d386ce3b72..4a17d80487 100644
--- a/src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/CompactObjectOutputStream.java
@@ -20,8 +20,6 @@ import java.io.ObjectOutputStream;
 import java.io.ObjectStreamClass;
 import java.io.OutputStream;
 
-/**
- */
 class CompactObjectOutputStream extends ObjectOutputStream {
 
     static final int TYPE_FAT_DESCRIPTOR = 0;
@@ -39,7 +37,7 @@ class CompactObjectOutputStream extends ObjectOutputStream {
     @Override
     protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
         Class clazz = desc.forClass();
-        if (clazz.isPrimitive() || clazz.isArray()) {
+        if (clazz.isPrimitive() || clazz.isArray() || desc.getSerialVersionUID() == 0) {
             write(TYPE_FAT_DESCRIPTOR);
             super.writeClassDescriptor(desc);
         } else {
diff --git a/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoder.java b/codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java b/codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java
index 9ed1109b9a..a98fbc99cc 100644
--- a/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectDecoderState.java
@@ -15,8 +15,6 @@
  */
 package io.netty.handler.codec.serialization;
 
-/**
- */
 enum CompatibleObjectDecoderState {
     READ_HEADER,
     READ_OBJECT,
diff --git a/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectEncoder.java b/codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/CompatibleObjectEncoder.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/CompatibleObjectEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java
similarity index 99%
rename from src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java
index 7a0a642f95..64a2f9049b 100644
--- a/src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoder.java
@@ -97,6 +97,7 @@ public class ObjectDecoder extends LengthFieldBasedFrameDecoder {
 
     /**
      * Create a new decoder with the specified maximum object size and the {@link ClassLoader} wrapped in {@link ClassResolvers#weakCachingResolver(ClassLoader)}
+     *
      * @param maxObjectSize  the maximum byte length of the serialized object.
      *                       if the length of the received object is greater
      *                       than this value, {@link StreamCorruptedException}
diff --git a/src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java
similarity index 98%
rename from src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java
index 0d9daece52..3772b87eb6 100644
--- a/src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java
+++ b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectDecoderInputStream.java
@@ -191,6 +191,9 @@ public class ObjectDecoderInputStream extends InputStream implements
         return in.readInt();
     }
 
+    /**
+     * @deprecated Use {@link java.io.BufferedReader#readLine()} instead.
+     */
     @Override
     @Deprecated
     public final String readLine() throws IOException {
diff --git a/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ObjectEncoderOutputStream.java b/codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoderOutputStream.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/ObjectEncoderOutputStream.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ObjectEncoderOutputStream.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/ReferenceMap.java b/codec/src/main/java/io/netty/handler/codec/serialization/ReferenceMap.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/ReferenceMap.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/ReferenceMap.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/SoftReferenceMap.java b/codec/src/main/java/io/netty/handler/codec/serialization/SoftReferenceMap.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/SoftReferenceMap.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/SoftReferenceMap.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/SwitchableInputStream.java b/codec/src/main/java/io/netty/handler/codec/serialization/SwitchableInputStream.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/SwitchableInputStream.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/SwitchableInputStream.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/WeakReferenceMap.java b/codec/src/main/java/io/netty/handler/codec/serialization/WeakReferenceMap.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/WeakReferenceMap.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/WeakReferenceMap.java
diff --git a/src/main/java/io/netty/handler/codec/serialization/package-info.java b/codec/src/main/java/io/netty/handler/codec/serialization/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/serialization/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/serialization/package-info.java
diff --git a/src/main/java/io/netty/handler/codec/string/StringDecoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/string/StringDecoder.java
rename to codec/src/main/java/io/netty/handler/codec/string/StringDecoder.java
diff --git a/src/main/java/io/netty/handler/codec/string/StringEncoder.java b/codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/string/StringEncoder.java
rename to codec/src/main/java/io/netty/handler/codec/string/StringEncoder.java
diff --git a/src/main/java/io/netty/handler/codec/string/package-info.java b/codec/src/main/java/io/netty/handler/codec/string/package-info.java
similarity index 100%
rename from src/main/java/io/netty/handler/codec/string/package-info.java
rename to codec/src/main/java/io/netty/handler/codec/string/package-info.java
diff --git a/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java
similarity index 100%
rename from src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayDecoderTest.java
diff --git a/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java b/codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java
similarity index 100%
rename from src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/bytes/ByteArrayEncoderTest.java
diff --git a/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java
index 7d1728de7a..d183af4ae9 100644
--- a/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/frame/DelimiterBasedFrameDecoderTest.java
@@ -23,8 +23,6 @@ import io.netty.util.CharsetUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
-/**
- */
 public class DelimiterBasedFrameDecoderTest {
     @Test
     public void testFailSlowTooLongFrameRecovery() throws Exception {
diff --git a/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java
index 7e24821b34..5d756bc232 100644
--- a/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldBasedFrameDecoderTest.java
@@ -23,8 +23,6 @@ import io.netty.util.CharsetUtil;
 import org.junit.Assert;
 import org.junit.Test;
 
-/**
- */
 public class LengthFieldBasedFrameDecoderTest {
     @Test
     public void testFailSlowTooLongFrameRecovery() throws Exception {
diff --git a/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java
index 29259fae9d..9c32400375 100644
--- a/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32FrameDecoderTest.java
@@ -25,8 +25,6 @@ import io.netty.handler.codec.embedder.DecoderEmbedder;
 import org.junit.Before;
 import org.junit.Test;
 
-/**
- */
 public class ProtobufVarint32FrameDecoderTest {
 
     private DecoderEmbedder embedder;
diff --git a/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java
rename to codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java
index d650942628..93ae7b2ba1 100644
--- a/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/protobuf/ProtobufVarint32LengthFieldPrependerTest.java
@@ -24,8 +24,6 @@ import io.netty.handler.codec.embedder.EncoderEmbedder;
 import org.junit.Before;
 import org.junit.Test;
 
-/**
- */
 public class ProtobufVarint32LengthFieldPrependerTest {
 
     private EncoderEmbedder embedder;
diff --git a/src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java
rename to codec/src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java
index a96b0c6ff7..1b8af565b8 100644
--- a/src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/replay/ReplayingDecoderTest.java
@@ -25,8 +25,6 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.embedder.DecoderEmbedder;
 import org.junit.Test;
 
-/**
- */
 public class ReplayingDecoderTest {
 
     @Test
diff --git a/src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java b/codec/src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java
similarity index 99%
rename from src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java
rename to codec/src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java
index 23953ec468..ceb77f0468 100644
--- a/src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/serialization/CompactObjectSerializationTest.java
@@ -22,8 +22,6 @@ import java.util.List;
 import org.junit.Assert;
 import org.junit.Test;
 
-/**
- */
 public class CompactObjectSerializationTest {
 
     @Test
diff --git a/src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java b/codec/src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java
similarity index 95%
rename from src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java
rename to codec/src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java
index f92e11e7c3..2ec1f782f7 100644
--- a/src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java
+++ b/codec/src/test/java/io/netty/handler/codec/serialization/SwitchableInputStreamTest.java
@@ -16,16 +16,12 @@
 package io.netty.handler.codec.serialization;
 
 import static org.easymock.EasyMock.*;
-import static org.easymock.classextension.EasyMock.*;
 import static org.junit.Assert.*;
 
 import java.io.InputStream;
 
 import org.junit.Test;
 
-
-/**
- */
 public class SwitchableInputStreamTest {
 
     @Test
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 0000000000..24edd61632
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+
+  4.0.0
+  
+    io.netty
+    netty-parent
+    4.0.0.Alpha1-SNAPSHOT
+  
+
+  io.netty
+  netty-common
+  jar
+
+  Netty/Common
+
+  
+    
+    
+      org.slf4j
+      slf4j-api
+      compile
+      true
+    
+    
+      commons-logging
+      commons-logging
+      compile
+      true
+    
+    
+      org.jboss.logging
+      jboss-logging-spi
+      compile
+      true
+    
+    
+      log4j
+      log4j
+      compile
+      true
+    
+    
+      org.apache.felix
+      org.osgi.core
+      compile
+      true
+    
+    
+      org.apache.felix
+      org.osgi.compendium
+      compile
+      true
+    
+  
+
+  
+    
+    
+  
+
+
diff --git a/src/main/java/io/netty/logging/AbstractInternalLogger.java b/common/src/main/java/io/netty/logging/AbstractInternalLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/AbstractInternalLogger.java
rename to common/src/main/java/io/netty/logging/AbstractInternalLogger.java
diff --git a/src/main/java/io/netty/logging/CommonsLogger.java b/common/src/main/java/io/netty/logging/CommonsLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/CommonsLogger.java
rename to common/src/main/java/io/netty/logging/CommonsLogger.java
diff --git a/src/main/java/io/netty/logging/CommonsLoggerFactory.java b/common/src/main/java/io/netty/logging/CommonsLoggerFactory.java
similarity index 100%
rename from src/main/java/io/netty/logging/CommonsLoggerFactory.java
rename to common/src/main/java/io/netty/logging/CommonsLoggerFactory.java
diff --git a/src/main/java/io/netty/logging/InternalLogLevel.java b/common/src/main/java/io/netty/logging/InternalLogLevel.java
similarity index 100%
rename from src/main/java/io/netty/logging/InternalLogLevel.java
rename to common/src/main/java/io/netty/logging/InternalLogLevel.java
diff --git a/src/main/java/io/netty/logging/InternalLogger.java b/common/src/main/java/io/netty/logging/InternalLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/InternalLogger.java
rename to common/src/main/java/io/netty/logging/InternalLogger.java
diff --git a/src/main/java/io/netty/logging/InternalLoggerFactory.java b/common/src/main/java/io/netty/logging/InternalLoggerFactory.java
similarity index 89%
rename from src/main/java/io/netty/logging/InternalLoggerFactory.java
rename to common/src/main/java/io/netty/logging/InternalLoggerFactory.java
index 54052c969c..badb9d88cf 100644
--- a/src/main/java/io/netty/logging/InternalLoggerFactory.java
+++ b/common/src/main/java/io/netty/logging/InternalLoggerFactory.java
@@ -15,8 +15,6 @@
  */
 package io.netty.logging;
 
-import io.netty.util.internal.StackTraceSimplifier;
-
 /**
  * Creates an {@link InternalLogger} or changes the default factory
  * implementation.  This factory allows you to choose what logging framework
@@ -36,13 +34,6 @@ import io.netty.util.internal.StackTraceSimplifier;
 public abstract class InternalLoggerFactory {
     private static volatile InternalLoggerFactory defaultFactory = new JdkLoggerFactory();
 
-    static {
-        // Load the dependent classes in advance to avoid the case where
-        // the VM fails to load the required classes because of too many open
-        // files.
-        StackTraceSimplifier.simplify(new Exception());
-    }
-
     /**
      * Returns the default factory.  The initial default factory is
      * {@link JdkLoggerFactory}.
@@ -82,7 +73,6 @@ public abstract class InternalLoggerFactory {
 
             @Override
             public void debug(String msg, Throwable cause) {
-                StackTraceSimplifier.simplify(cause);
                 logger.debug(msg, cause);
             }
 
@@ -93,7 +83,6 @@ public abstract class InternalLoggerFactory {
 
             @Override
             public void error(String msg, Throwable cause) {
-                StackTraceSimplifier.simplify(cause);
                 logger.error(msg, cause);
             }
 
@@ -104,7 +93,6 @@ public abstract class InternalLoggerFactory {
 
             @Override
             public void info(String msg, Throwable cause) {
-                StackTraceSimplifier.simplify(cause);
                 logger.info(msg, cause);
             }
 
@@ -135,7 +123,6 @@ public abstract class InternalLoggerFactory {
 
             @Override
             public void warn(String msg, Throwable cause) {
-                StackTraceSimplifier.simplify(cause);
                 logger.warn(msg, cause);
             }
 
@@ -151,7 +138,6 @@ public abstract class InternalLoggerFactory {
 
             @Override
             public void log(InternalLogLevel level, String msg, Throwable cause) {
-                StackTraceSimplifier.simplify(cause);
                 logger.log(level, msg, cause);
             }
         };
diff --git a/src/main/java/io/netty/logging/JBossLogger.java b/common/src/main/java/io/netty/logging/JBossLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/JBossLogger.java
rename to common/src/main/java/io/netty/logging/JBossLogger.java
diff --git a/src/main/java/io/netty/logging/JBossLoggerFactory.java b/common/src/main/java/io/netty/logging/JBossLoggerFactory.java
similarity index 100%
rename from src/main/java/io/netty/logging/JBossLoggerFactory.java
rename to common/src/main/java/io/netty/logging/JBossLoggerFactory.java
diff --git a/src/main/java/io/netty/logging/JdkLogger.java b/common/src/main/java/io/netty/logging/JdkLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/JdkLogger.java
rename to common/src/main/java/io/netty/logging/JdkLogger.java
diff --git a/src/main/java/io/netty/logging/JdkLoggerFactory.java b/common/src/main/java/io/netty/logging/JdkLoggerFactory.java
similarity index 100%
rename from src/main/java/io/netty/logging/JdkLoggerFactory.java
rename to common/src/main/java/io/netty/logging/JdkLoggerFactory.java
diff --git a/src/main/java/io/netty/logging/Log4JLogger.java b/common/src/main/java/io/netty/logging/Log4JLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/Log4JLogger.java
rename to common/src/main/java/io/netty/logging/Log4JLogger.java
diff --git a/src/main/java/io/netty/logging/Log4JLoggerFactory.java b/common/src/main/java/io/netty/logging/Log4JLoggerFactory.java
similarity index 99%
rename from src/main/java/io/netty/logging/Log4JLoggerFactory.java
rename to common/src/main/java/io/netty/logging/Log4JLoggerFactory.java
index 45812f29cf..17b52c1074 100644
--- a/src/main/java/io/netty/logging/Log4JLoggerFactory.java
+++ b/common/src/main/java/io/netty/logging/Log4JLoggerFactory.java
@@ -15,8 +15,6 @@
  */
 package io.netty.logging;
 
-
-
 /**
  * Logger factory which creates an
  * Apache Log4J
diff --git a/src/main/java/io/netty/logging/OsgiLogger.java b/common/src/main/java/io/netty/logging/OsgiLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/OsgiLogger.java
rename to common/src/main/java/io/netty/logging/OsgiLogger.java
diff --git a/src/main/java/io/netty/logging/OsgiLoggerFactory.java b/common/src/main/java/io/netty/logging/OsgiLoggerFactory.java
similarity index 100%
rename from src/main/java/io/netty/logging/OsgiLoggerFactory.java
rename to common/src/main/java/io/netty/logging/OsgiLoggerFactory.java
diff --git a/src/main/java/io/netty/logging/Slf4JLogger.java b/common/src/main/java/io/netty/logging/Slf4JLogger.java
similarity index 100%
rename from src/main/java/io/netty/logging/Slf4JLogger.java
rename to common/src/main/java/io/netty/logging/Slf4JLogger.java
diff --git a/src/main/java/io/netty/logging/Slf4JLoggerFactory.java b/common/src/main/java/io/netty/logging/Slf4JLoggerFactory.java
similarity index 100%
rename from src/main/java/io/netty/logging/Slf4JLoggerFactory.java
rename to common/src/main/java/io/netty/logging/Slf4JLoggerFactory.java
diff --git a/src/main/java/io/netty/logging/package-info.java b/common/src/main/java/io/netty/logging/package-info.java
similarity index 100%
rename from src/main/java/io/netty/logging/package-info.java
rename to common/src/main/java/io/netty/logging/package-info.java
diff --git a/src/main/java/io/netty/util/CharsetUtil.java b/common/src/main/java/io/netty/util/CharsetUtil.java
similarity index 96%
rename from src/main/java/io/netty/util/CharsetUtil.java
rename to common/src/main/java/io/netty/util/CharsetUtil.java
index df0c4bcfb6..49c44641cf 100644
--- a/src/main/java/io/netty/util/CharsetUtil.java
+++ b/common/src/main/java/io/netty/util/CharsetUtil.java
@@ -26,7 +26,7 @@ import java.util.Map;
  * A utility class that provides various common operations and constants
  * related with {@link Charset} and its relevant classes.
  */
-public class CharsetUtil {
+public final class CharsetUtil {
 
     /**
      * 16-bit UTF (UCS Transformation Format) whose byte order is identified by
@@ -61,7 +61,7 @@ public class CharsetUtil {
     public static final Charset US_ASCII = Charset.forName("US-ASCII");
 
     private static final ThreadLocal> encoders =
-        new ThreadLocal>() {
+        new ThreadLocal>() {
             @Override
             protected Map initialValue() {
                 return new IdentityHashMap();
@@ -69,7 +69,7 @@ public class CharsetUtil {
         };
 
     private static final ThreadLocal> decoders =
-        new ThreadLocal>() {
+        new ThreadLocal>() {
             @Override
             protected Map initialValue() {
                 return new IdentityHashMap();
diff --git a/src/main/java/io/netty/util/EstimatableObjectWrapper.java b/common/src/main/java/io/netty/util/EstimatableObjectWrapper.java
similarity index 100%
rename from src/main/java/io/netty/util/EstimatableObjectWrapper.java
rename to common/src/main/java/io/netty/util/EstimatableObjectWrapper.java
diff --git a/src/main/java/io/netty/util/ExternalResourceReleasable.java b/common/src/main/java/io/netty/util/ExternalResourceReleasable.java
similarity index 100%
rename from src/main/java/io/netty/util/ExternalResourceReleasable.java
rename to common/src/main/java/io/netty/util/ExternalResourceReleasable.java
diff --git a/src/main/java/io/netty/util/ExternalResourceUtil.java b/common/src/main/java/io/netty/util/ExternalResourceUtil.java
similarity index 97%
rename from src/main/java/io/netty/util/ExternalResourceUtil.java
rename to common/src/main/java/io/netty/util/ExternalResourceUtil.java
index afdb5d7162..46fcda5d02 100644
--- a/src/main/java/io/netty/util/ExternalResourceUtil.java
+++ b/common/src/main/java/io/netty/util/ExternalResourceUtil.java
@@ -19,7 +19,7 @@ package io.netty.util;
  * A utility class that provides the convenient shutdown of
  * {@link ExternalResourceReleasable}s.
  */
-public class ExternalResourceUtil {
+public final class ExternalResourceUtil {
 
     /**
      * Releases the specified {@link ExternalResourceReleasable}s.
diff --git a/src/main/java/io/netty/util/HashedWheelTimer.java b/common/src/main/java/io/netty/util/HashedWheelTimer.java
similarity index 98%
rename from src/main/java/io/netty/util/HashedWheelTimer.java
rename to common/src/main/java/io/netty/util/HashedWheelTimer.java
index 8f0ec16847..c8f200c2ec 100644
--- a/src/main/java/io/netty/util/HashedWheelTimer.java
+++ b/common/src/main/java/io/netty/util/HashedWheelTimer.java
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import io.netty.channel.ChannelPipelineFactory;
 import io.netty.logging.InternalLogger;
 import io.netty.logging.InternalLoggerFactory;
 import io.netty.util.internal.ConcurrentIdentityHashMap;
@@ -64,9 +63,7 @@ import io.netty.util.internal.SharedResourceMisuseDetector;
  * {@link HashedWheelTimer} creates a new thread whenever it is instantiated and
  * started.  Therefore, you should make sure to create only one instance and
  * share it across your application.  One of the common mistakes, that makes
- * your application unresponsive, is to create a new instance in
- * {@link ChannelPipelineFactory}, which results in the creation of a new thread
- * for every connection.
+ * your application unresponsive, is to create a new instance for every connection.
  *
  * 

Implementation Details

* @@ -548,7 +545,7 @@ public class HashedWheelTimer implements Timer { } if (isCancelled()) { - buf.append (", cancelled"); + buf.append(", cancelled"); } return buf.append(')').toString(); diff --git a/src/main/java/io/netty/util/MapBackedSet.java b/common/src/main/java/io/netty/util/MapBackedSet.java similarity index 100% rename from src/main/java/io/netty/util/MapBackedSet.java rename to common/src/main/java/io/netty/util/MapBackedSet.java diff --git a/src/test/java/io/netty/util/TestUtil.java b/common/src/main/java/io/netty/util/SocketAddresses.java similarity index 88% rename from src/test/java/io/netty/util/TestUtil.java rename to common/src/main/java/io/netty/util/SocketAddresses.java index a57824f6c0..edc0ef6220 100644 --- a/src/test/java/io/netty/util/TestUtil.java +++ b/common/src/main/java/io/netty/util/SocketAddresses.java @@ -18,15 +18,14 @@ package io.netty.util; import java.net.InetAddress; import java.net.UnknownHostException; +public final class SocketAddresses { -/** - */ -@org.junit.Ignore -public final class TestUtil { - - private static final InetAddress LOCALHOST; + public static final InetAddress LOCALHOST; static { + // We cache this because some machine takes almost forever to return + // from InetAddress.getLocalHost(). I think it's due to the incorrect + // /etc/hosts or /etc/resolve.conf. InetAddress localhost = null; try { localhost = InetAddress.getLocalHost(); @@ -46,14 +45,7 @@ public final class TestUtil { LOCALHOST = localhost; } - public static InetAddress getLocalHost() { - // We cache this because some machine takes almost forever to return - // from InetAddress.getLocalHost(). I think it's due to the incorrect - // /etc/hosts or /etc/resolve.conf. - return LOCALHOST; - } - - private TestUtil() { + private SocketAddresses() { // Unused } } diff --git a/src/main/java/io/netty/util/Timeout.java b/common/src/main/java/io/netty/util/Timeout.java similarity index 100% rename from src/main/java/io/netty/util/Timeout.java rename to common/src/main/java/io/netty/util/Timeout.java diff --git a/src/main/java/io/netty/util/Timer.java b/common/src/main/java/io/netty/util/Timer.java similarity index 100% rename from src/main/java/io/netty/util/Timer.java rename to common/src/main/java/io/netty/util/Timer.java diff --git a/src/main/java/io/netty/util/TimerTask.java b/common/src/main/java/io/netty/util/TimerTask.java similarity index 100% rename from src/main/java/io/netty/util/TimerTask.java rename to common/src/main/java/io/netty/util/TimerTask.java diff --git a/src/main/java/io/netty/util/UnsafeDetectUtil.java b/common/src/main/java/io/netty/util/UnsafeDetectUtil.java similarity index 54% rename from src/main/java/io/netty/util/UnsafeDetectUtil.java rename to common/src/main/java/io/netty/util/UnsafeDetectUtil.java index 97b909b191..4c88541ab1 100644 --- a/src/main/java/io/netty/util/UnsafeDetectUtil.java +++ b/common/src/main/java/io/netty/util/UnsafeDetectUtil.java @@ -15,29 +15,45 @@ */ package io.netty.util; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.concurrent.atomic.AtomicInteger; /** * Utility which checks if {@value #UNSAFE} class can be found in the classpath - * - - + * and that it can be accessed using "theUnsafe" field which is not true for all platforms, i.e Android + * where it is called "THE_ONE". */ -public class UnsafeDetectUtil { +public final class UnsafeDetectUtil { + private static final String THE_UNSAFE = "theUnsafe"; private static final String UNSAFE = "sun.misc.Unsafe"; private static final boolean UNSAFE_FOUND = isUnsafeFound(AtomicInteger.class.getClassLoader()); public static boolean isUnsafeFound(ClassLoader loader) { try { - Class.forName(UNSAFE, true, loader); - return true; + Class unsafeClazz = Class.forName(UNSAFE, true, loader); + return hasUnsafeField(unsafeClazz); } catch (ClassNotFoundException e) { return false; + } catch (SecurityException e) { + return false; + } catch (PrivilegedActionException e) { + return false; } } - + + private static boolean hasUnsafeField(final Class unsafeClass) throws PrivilegedActionException { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Boolean run() throws Exception { + unsafeClass.getDeclaredField(THE_UNSAFE); + return true; + } + }); + } + public static boolean isUnsafeFound() { return UNSAFE_FOUND; } diff --git a/src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java b/common/src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java similarity index 93% rename from src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java rename to common/src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java index f4951b8e51..9399a18192 100644 --- a/src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java +++ b/common/src/main/java/io/netty/util/internal/AtomicFieldUpdaterUtil.java @@ -18,9 +18,7 @@ package io.netty.util.internal; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -/** - */ -class AtomicFieldUpdaterUtil { +final class AtomicFieldUpdaterUtil { private static final boolean AVAILABLE; @@ -49,7 +47,7 @@ class AtomicFieldUpdaterUtil { AVAILABLE = available; } - static AtomicReferenceFieldUpdater newRefUpdater(Class tclass, Class vclass, String fieldName) { + static AtomicReferenceFieldUpdater newRefUpdater(Class tclass, Class vclass, String fieldName) { if (AVAILABLE) { return AtomicReferenceFieldUpdater.newUpdater(tclass, vclass, fieldName); } else { diff --git a/src/main/java/io/netty/util/internal/ConcurrentHashMap.java b/common/src/main/java/io/netty/util/internal/ConcurrentHashMap.java similarity index 99% rename from src/main/java/io/netty/util/internal/ConcurrentHashMap.java rename to common/src/main/java/io/netty/util/internal/ConcurrentHashMap.java index 662481d3f4..a12b4ccc39 100644 --- a/src/main/java/io/netty/util/internal/ConcurrentHashMap.java +++ b/common/src/main/java/io/netty/util/internal/ConcurrentHashMap.java @@ -42,7 +42,7 @@ import java.util.concurrent.locks.ReentrantLock; * @param the type of mapped values */ public final class ConcurrentHashMap extends AbstractMap - implements ConcurrentMap{ + implements ConcurrentMap { /** * The default initial capacity for this table, used when not otherwise @@ -65,7 +65,7 @@ public final class ConcurrentHashMap extends AbstractMap /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two - * <= 1<<30 to ensure that entries are indexable using integers. + * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; @@ -262,7 +262,7 @@ public final class ConcurrentHashMap extends AbstractMap Segment(int initialCapacity, float lf) { loadFactor = lf; - setTable(HashEntry. newArray(initialCapacity)); + setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java b/common/src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java similarity index 99% rename from src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java rename to common/src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java index f16192ffa8..610bfd8c40 100644 --- a/src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java +++ b/common/src/main/java/io/netty/util/internal/ConcurrentIdentityHashMap.java @@ -42,7 +42,7 @@ import java.util.concurrent.locks.ReentrantLock; * @param the type of mapped values */ public final class ConcurrentIdentityHashMap extends AbstractMap - implements ConcurrentMap{ + implements ConcurrentMap { /** * The default initial capacity for this table, used when not otherwise @@ -65,7 +65,7 @@ public final class ConcurrentIdentityHashMap extends AbstractMap /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two - * <= 1<<30 to ensure that entries are indexable using integers. + * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; @@ -262,7 +262,7 @@ public final class ConcurrentIdentityHashMap extends AbstractMap Segment(int initialCapacity, float lf) { loadFactor = lf; - setTable(HashEntry. newArray(initialCapacity)); + setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java b/common/src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java similarity index 99% rename from src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java rename to common/src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java index 23aec45e5c..b2e791a9e7 100644 --- a/src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java +++ b/common/src/main/java/io/netty/util/internal/ConcurrentIdentityWeakKeyHashMap.java @@ -72,7 +72,7 @@ public final class ConcurrentIdentityWeakKeyHashMap extends AbstractMap extends AbstractMap newArray(initialCapacity)); + setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java b/common/src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java similarity index 99% rename from src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java rename to common/src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java index b716bfd27e..29cc6aa1ec 100644 --- a/src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java +++ b/common/src/main/java/io/netty/util/internal/ConcurrentWeakKeyHashMap.java @@ -72,7 +72,7 @@ public final class ConcurrentWeakKeyHashMap extends AbstractMap impl /** * The maximum capacity, used if a higher value is implicitly specified by * either of the constructors with arguments. MUST be a power of two - * <= 1<<30 to ensure that entries are indexable using integers. + * <= 1<<30 to ensure that entries are indexable using integers. */ static final int MAXIMUM_CAPACITY = 1 << 30; @@ -307,7 +307,7 @@ public final class ConcurrentWeakKeyHashMap extends AbstractMap impl Segment(int initialCapacity, float lf) { loadFactor = lf; - setTable(HashEntry. newArray(initialCapacity)); + setTable(HashEntry.newArray(initialCapacity)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/io/netty/util/internal/ConversionUtil.java b/common/src/main/java/io/netty/util/internal/ConversionUtil.java similarity index 95% rename from src/main/java/io/netty/util/internal/ConversionUtil.java rename to common/src/main/java/io/netty/util/internal/ConversionUtil.java index ea263aa997..f0ad66bea9 100644 --- a/src/main/java/io/netty/util/internal/ConversionUtil.java +++ b/common/src/main/java/io/netty/util/internal/ConversionUtil.java @@ -22,7 +22,7 @@ import java.util.List; * Conversion utility class to parse a property represented as a string or * an object. */ -public class ConversionUtil { +public final class ConversionUtil { /** * Converts the specified object into an integer. @@ -88,8 +88,8 @@ public class ConversionUtil { } private static final String[] INTEGERS = { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "10","11","12","13","14","15", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", }; public static String toString(int value) { diff --git a/src/main/java/io/netty/util/internal/DeadLockProofWorker.java b/common/src/main/java/io/netty/util/internal/DeadLockProofWorker.java similarity index 100% rename from src/main/java/io/netty/util/internal/DeadLockProofWorker.java rename to common/src/main/java/io/netty/util/internal/DeadLockProofWorker.java diff --git a/src/main/java/io/netty/util/internal/ExecutorUtil.java b/common/src/main/java/io/netty/util/internal/ExecutorUtil.java similarity index 99% rename from src/main/java/io/netty/util/internal/ExecutorUtil.java rename to common/src/main/java/io/netty/util/internal/ExecutorUtil.java index b7546ed2e6..3b40648796 100644 --- a/src/main/java/io/netty/util/internal/ExecutorUtil.java +++ b/common/src/main/java/io/netty/util/internal/ExecutorUtil.java @@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit; * their termination. An {@link Executor} which is not an {@link ExecutorService} * will be ignored silently. */ -public class ExecutorUtil { +public final class ExecutorUtil { /** * Returns {@code true} if and only if the specified {@code executor} diff --git a/src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java b/common/src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java similarity index 99% rename from src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java rename to common/src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java index 3fa4bdf9bd..f0168ea637 100644 --- a/src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java +++ b/common/src/main/java/io/netty/util/internal/LegacyLinkedTransferQueue.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.locks.LockSupport; + /** * * This version does work even if sun.misc.Unsafe is not found in the classpath. So this is kept for compatibility reasons. diff --git a/src/main/java/io/netty/util/internal/LinkedTransferQueue.java b/common/src/main/java/io/netty/util/internal/LinkedTransferQueue.java similarity index 100% rename from src/main/java/io/netty/util/internal/LinkedTransferQueue.java rename to common/src/main/java/io/netty/util/internal/LinkedTransferQueue.java diff --git a/src/main/java/io/netty/util/internal/NonReentrantLock.java b/common/src/main/java/io/netty/util/internal/NonReentrantLock.java similarity index 99% rename from src/main/java/io/netty/util/internal/NonReentrantLock.java rename to common/src/main/java/io/netty/util/internal/NonReentrantLock.java index 3cc3163548..129e792e8e 100644 --- a/src/main/java/io/netty/util/internal/NonReentrantLock.java +++ b/common/src/main/java/io/netty/util/internal/NonReentrantLock.java @@ -20,8 +20,6 @@ import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; -/** - */ public final class NonReentrantLock extends AbstractQueuedSynchronizer implements Lock { diff --git a/src/main/java/io/netty/util/internal/QueueFactory.java b/common/src/main/java/io/netty/util/internal/QueueFactory.java similarity index 85% rename from src/main/java/io/netty/util/internal/QueueFactory.java rename to common/src/main/java/io/netty/util/internal/QueueFactory.java index 575441787b..29b53acfd5 100644 --- a/src/main/java/io/netty/util/internal/QueueFactory.java +++ b/common/src/main/java/io/netty/util/internal/QueueFactory.java @@ -21,12 +21,10 @@ import java.util.concurrent.BlockingQueue; import io.netty.util.UnsafeDetectUtil; /** - * This factory should be used to create the "optimal" {@link BlockingQueue} instance for the running JVM. - * - - + * This factory should be used to create the "optimal" {@link BlockingQueue} + * instance for the running JVM. */ -public class QueueFactory { +public final class QueueFactory { private static final boolean useUnsafe = UnsafeDetectUtil.isUnsafeFound(QueueFactory.class.getClassLoader()); @@ -41,7 +39,7 @@ public class QueueFactory { * @param itemClass the {@link Class} type which will be used as {@link BlockingQueue} items * @return queue the {@link BlockingQueue} implementation */ - public static final BlockingQueue createQueue(Class itemClass) { + public static BlockingQueue createQueue(Class itemClass) { if (useUnsafe) { return new LinkedTransferQueue(); } else { @@ -56,7 +54,7 @@ public class QueueFactory { * @param itemClass the {@link Class} type which will be used as {@link BlockingQueue} items * @return queue the {@link BlockingQueue} implementation */ - public static final BlockingQueue createQueue(Collection collection, Class itemClass) { + public static BlockingQueue createQueue(Collection collection, Class itemClass) { if (useUnsafe) { return new LinkedTransferQueue(collection); } else { diff --git a/src/main/java/io/netty/util/internal/ReusableIterator.java b/common/src/main/java/io/netty/util/internal/ReusableIterator.java similarity index 98% rename from src/main/java/io/netty/util/internal/ReusableIterator.java rename to common/src/main/java/io/netty/util/internal/ReusableIterator.java index 019e24bed7..f821ef9670 100644 --- a/src/main/java/io/netty/util/internal/ReusableIterator.java +++ b/common/src/main/java/io/netty/util/internal/ReusableIterator.java @@ -17,8 +17,6 @@ package io.netty.util.internal; import java.util.Iterator; -/** - */ public interface ReusableIterator extends Iterator { void rewind(); } diff --git a/src/main/java/io/netty/util/internal/SharedResourceMisuseDetector.java b/common/src/main/java/io/netty/util/internal/SharedResourceMisuseDetector.java similarity index 100% rename from src/main/java/io/netty/util/internal/SharedResourceMisuseDetector.java rename to common/src/main/java/io/netty/util/internal/SharedResourceMisuseDetector.java diff --git a/src/main/java/io/netty/util/internal/StringUtil.java b/common/src/main/java/io/netty/util/internal/StringUtil.java similarity index 99% rename from src/main/java/io/netty/util/internal/StringUtil.java rename to common/src/main/java/io/netty/util/internal/StringUtil.java index 95540f1e30..ee0ab0ffa1 100644 --- a/src/main/java/io/netty/util/internal/StringUtil.java +++ b/common/src/main/java/io/netty/util/internal/StringUtil.java @@ -20,7 +20,7 @@ import java.util.Formatter; /** * String utility class. */ -public class StringUtil { +public final class StringUtil { private StringUtil() { // Unused. diff --git a/src/main/java/io/netty/util/internal/SystemPropertyUtil.java b/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java similarity index 98% rename from src/main/java/io/netty/util/internal/SystemPropertyUtil.java rename to common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java index fde1761f91..dcdcaa41a8 100644 --- a/src/main/java/io/netty/util/internal/SystemPropertyUtil.java +++ b/common/src/main/java/io/netty/util/internal/SystemPropertyUtil.java @@ -20,7 +20,7 @@ import java.util.regex.Pattern; /** * Accesses the system property swallowing a {@link SecurityException}. */ -public class SystemPropertyUtil { +public final class SystemPropertyUtil { /** * Returns the value of the Java system property with the specified diff --git a/src/main/java/io/netty/util/internal/ThreadLocalBoolean.java b/common/src/main/java/io/netty/util/internal/ThreadLocalBoolean.java similarity index 99% rename from src/main/java/io/netty/util/internal/ThreadLocalBoolean.java rename to common/src/main/java/io/netty/util/internal/ThreadLocalBoolean.java index be60001439..af526cddfe 100644 --- a/src/main/java/io/netty/util/internal/ThreadLocalBoolean.java +++ b/common/src/main/java/io/netty/util/internal/ThreadLocalBoolean.java @@ -15,8 +15,6 @@ */ package io.netty.util.internal; -/** - */ public class ThreadLocalBoolean extends ThreadLocal { private final boolean defaultValue; diff --git a/src/main/java/io/netty/util/internal/ThreadLocalRandom.java b/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java similarity index 95% rename from src/main/java/io/netty/util/internal/ThreadLocalRandom.java rename to common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java index 11959f9e15..0afb9ce258 100644 --- a/src/main/java/io/netty/util/internal/ThreadLocalRandom.java +++ b/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java @@ -48,9 +48,9 @@ import java.util.Random; */ final class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; /** * The random seed. We can't use super.seed. @@ -118,7 +118,7 @@ final class ThreadLocalRandom extends Random { @Override protected int next(int bits) { rnd = rnd * multiplier + addend & mask; - return (int) (rnd >>> 48-bits); + return (int) (rnd >>> 48 - bits); } private static final long serialVersionUID = -5851777807851030925L; diff --git a/src/main/java/io/netty/util/internal/UnterminatableExecutor.java b/common/src/main/java/io/netty/util/internal/UnterminatableExecutor.java similarity index 100% rename from src/main/java/io/netty/util/internal/UnterminatableExecutor.java rename to common/src/main/java/io/netty/util/internal/UnterminatableExecutor.java diff --git a/src/main/java/io/netty/util/internal/jzlib/Adler32.java b/common/src/main/java/io/netty/util/internal/jzlib/Adler32.java similarity index 66% rename from src/main/java/io/netty/util/internal/jzlib/Adler32.java rename to common/src/main/java/io/netty/util/internal/jzlib/Adler32.java index 13a8cefaa8..8e5f00c834 100644 --- a/src/main/java/io/netty/util/internal/jzlib/Adler32.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/Adler32.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class Adler32 { diff --git a/src/main/java/io/netty/util/internal/jzlib/CRC32.java b/common/src/main/java/io/netty/util/internal/jzlib/CRC32.java similarity index 72% rename from src/main/java/io/netty/util/internal/jzlib/CRC32.java rename to common/src/main/java/io/netty/util/internal/jzlib/CRC32.java index e65f32e51c..c6b17f0876 100644 --- a/src/main/java/io/netty/util/internal/jzlib/CRC32.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/CRC32.java @@ -13,6 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ package io.netty.util.internal.jzlib; final class CRC32 { diff --git a/src/main/java/io/netty/util/internal/jzlib/Deflate.java b/common/src/main/java/io/netty/util/internal/jzlib/Deflate.java similarity index 97% rename from src/main/java/io/netty/util/internal/jzlib/Deflate.java rename to common/src/main/java/io/netty/util/internal/jzlib/Deflate.java index a0fb3812d0..4d45145b86 100644 --- a/src/main/java/io/netty/util/internal/jzlib/Deflate.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/Deflate.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; import io.netty.util.internal.jzlib.JZlib.WrapperType; @@ -1271,9 +1296,9 @@ final class Deflate { return lookahead; } - int deflateInit(ZStream strm, int level, int bits, WrapperType wrapperType) { + int deflateInit(ZStream strm, int level, int bits, int memLevel, WrapperType wrapperType) { return deflateInit2(strm, level, JZlib.Z_DEFLATED, bits, - JZlib.DEF_MEM_LEVEL, JZlib.Z_DEFAULT_STRATEGY, wrapperType); + memLevel, JZlib.Z_DEFAULT_STRATEGY, wrapperType); } private int deflateInit2(ZStream strm, int level, int method, int windowBits, diff --git a/src/main/java/io/netty/util/internal/jzlib/InfBlocks.java b/common/src/main/java/io/netty/util/internal/jzlib/InfBlocks.java similarity index 93% rename from src/main/java/io/netty/util/internal/jzlib/InfBlocks.java rename to common/src/main/java/io/netty/util/internal/jzlib/InfBlocks.java index 2af281e50e..b387ffbb1c 100644 --- a/src/main/java/io/netty/util/internal/jzlib/InfBlocks.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/InfBlocks.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class InfBlocks { diff --git a/src/main/java/io/netty/util/internal/jzlib/InfCodes.java b/common/src/main/java/io/netty/util/internal/jzlib/InfCodes.java similarity index 94% rename from src/main/java/io/netty/util/internal/jzlib/InfCodes.java rename to common/src/main/java/io/netty/util/internal/jzlib/InfCodes.java index ae23c56cc6..ef979b57a3 100644 --- a/src/main/java/io/netty/util/internal/jzlib/InfCodes.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/InfCodes.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class InfCodes { diff --git a/src/main/java/io/netty/util/internal/jzlib/InfTree.java b/common/src/main/java/io/netty/util/internal/jzlib/InfTree.java similarity index 93% rename from src/main/java/io/netty/util/internal/jzlib/InfTree.java rename to common/src/main/java/io/netty/util/internal/jzlib/InfTree.java index 64ab9554cd..313c1789f6 100644 --- a/src/main/java/io/netty/util/internal/jzlib/InfTree.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/InfTree.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class InfTree { diff --git a/src/main/java/io/netty/util/internal/jzlib/Inflate.java b/common/src/main/java/io/netty/util/internal/jzlib/Inflate.java similarity index 93% rename from src/main/java/io/netty/util/internal/jzlib/Inflate.java rename to common/src/main/java/io/netty/util/internal/jzlib/Inflate.java index a7898f9d45..c496533203 100644 --- a/src/main/java/io/netty/util/internal/jzlib/Inflate.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/Inflate.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; import io.netty.util.internal.jzlib.JZlib.WrapperType; diff --git a/src/main/java/io/netty/util/internal/jzlib/JZlib.java b/common/src/main/java/io/netty/util/internal/jzlib/JZlib.java similarity index 67% rename from src/main/java/io/netty/util/internal/jzlib/JZlib.java rename to common/src/main/java/io/netty/util/internal/jzlib/JZlib.java index aa46e37da2..b97f96a878 100644 --- a/src/main/java/io/netty/util/internal/jzlib/JZlib.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/JZlib.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; public final class JZlib { diff --git a/src/main/java/io/netty/util/internal/jzlib/StaticTree.java b/common/src/main/java/io/netty/util/internal/jzlib/StaticTree.java similarity index 76% rename from src/main/java/io/netty/util/internal/jzlib/StaticTree.java rename to common/src/main/java/io/netty/util/internal/jzlib/StaticTree.java index ce6e6ea455..8ccb3bd314 100644 --- a/src/main/java/io/netty/util/internal/jzlib/StaticTree.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/StaticTree.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class StaticTree { diff --git a/src/main/java/io/netty/util/internal/jzlib/Tree.java b/common/src/main/java/io/netty/util/internal/jzlib/Tree.java similarity index 90% rename from src/main/java/io/netty/util/internal/jzlib/Tree.java rename to common/src/main/java/io/netty/util/internal/jzlib/Tree.java index e90ee3056e..96b22af6e7 100644 --- a/src/main/java/io/netty/util/internal/jzlib/Tree.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/Tree.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; final class Tree { diff --git a/src/main/java/io/netty/util/internal/jzlib/ZStream.java b/common/src/main/java/io/netty/util/internal/jzlib/ZStream.java similarity index 77% rename from src/main/java/io/netty/util/internal/jzlib/ZStream.java rename to common/src/main/java/io/netty/util/internal/jzlib/ZStream.java index 9bc28c205f..0d4f2a343a 100644 --- a/src/main/java/io/netty/util/internal/jzlib/ZStream.java +++ b/common/src/main/java/io/netty/util/internal/jzlib/ZStream.java @@ -13,13 +13,38 @@ * License for the specific language governing permissions and limitations * under the License. */ +/* +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * This program is based on zlib-1.1.3, so all credit should go authors * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) * and contributors of zlib. */ - package io.netty.util.internal.jzlib; import io.netty.util.internal.jzlib.JZlib.WrapperType; @@ -99,9 +124,13 @@ public final class ZStream { return deflateInit(level, bits, WrapperType.ZLIB); } - public int deflateInit(int level, int bits, @SuppressWarnings("rawtypes") Enum wrapperType) { + public int deflateInit(int level, int bits, Enum wrapperType) { + return deflateInit(level, bits, JZlib.DEF_MEM_LEVEL, wrapperType); + } + + public int deflateInit(int level, int bits, int memLevel, @SuppressWarnings("rawtypes") Enum wrapperType) { dstate = new Deflate(); - return dstate.deflateInit(this, level, bits, (WrapperType) wrapperType); + return dstate.deflateInit(this, level, bits, memLevel, (WrapperType) wrapperType); } public int deflate(int flush) { diff --git a/src/main/java/io/netty/util/internal/package-info.java b/common/src/main/java/io/netty/util/internal/package-info.java similarity index 100% rename from src/main/java/io/netty/util/internal/package-info.java rename to common/src/main/java/io/netty/util/internal/package-info.java diff --git a/src/main/java/io/netty/util/package-info.java b/common/src/main/java/io/netty/util/package-info.java similarity index 100% rename from src/main/java/io/netty/util/package-info.java rename to common/src/main/java/io/netty/util/package-info.java diff --git a/src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java similarity index 99% rename from src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java index 90f4509abc..85caa03ee1 100644 --- a/src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/CommonsLoggerFactoryTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class CommonsLoggerFactoryTest { @Test diff --git a/src/test/java/io/netty/logging/CommonsLoggerTest.java b/common/src/test/java/io/netty/logging/CommonsLoggerTest.java similarity index 99% rename from src/test/java/io/netty/logging/CommonsLoggerTest.java rename to common/src/test/java/io/netty/logging/CommonsLoggerTest.java index 0bdb7327c5..85c10cda53 100644 --- a/src/test/java/io/netty/logging/CommonsLoggerTest.java +++ b/common/src/test/java/io/netty/logging/CommonsLoggerTest.java @@ -20,9 +20,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class CommonsLoggerTest { private static final Exception e = new Exception(); diff --git a/src/test/java/io/netty/logging/InternalLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/InternalLoggerFactoryTest.java similarity index 98% rename from src/test/java/io/netty/logging/InternalLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/InternalLoggerFactoryTest.java index b9771d335c..3dd15881f2 100644 --- a/src/test/java/io/netty/logging/InternalLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/InternalLoggerFactoryTest.java @@ -16,16 +16,12 @@ package io.netty.logging; import static org.easymock.EasyMock.*; -import static org.easymock.classextension.EasyMock.*; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; - -/** - */ public class InternalLoggerFactoryTest { private static final Exception e = new Exception(); private InternalLoggerFactory oldLoggerFactory; diff --git a/src/test/java/io/netty/logging/JBossLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/JBossLoggerFactoryTest.java similarity index 99% rename from src/test/java/io/netty/logging/JBossLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/JBossLoggerFactoryTest.java index 2ef952c366..865d723d78 100644 --- a/src/test/java/io/netty/logging/JBossLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/JBossLoggerFactoryTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class JBossLoggerFactoryTest { @Test diff --git a/src/test/java/io/netty/logging/JBossLoggerTest.java b/common/src/test/java/io/netty/logging/JBossLoggerTest.java similarity index 98% rename from src/test/java/io/netty/logging/JBossLoggerTest.java rename to common/src/test/java/io/netty/logging/JBossLoggerTest.java index 39cdfd39b8..f9ac13e463 100644 --- a/src/test/java/io/netty/logging/JBossLoggerTest.java +++ b/common/src/test/java/io/netty/logging/JBossLoggerTest.java @@ -16,14 +16,10 @@ package io.netty.logging; import static org.easymock.EasyMock.*; -import static org.easymock.classextension.EasyMock.*; import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class JBossLoggerTest { private static final Exception e = new Exception(); diff --git a/src/test/java/io/netty/logging/JdkLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/JdkLoggerFactoryTest.java similarity index 99% rename from src/test/java/io/netty/logging/JdkLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/JdkLoggerFactoryTest.java index 93c2a5fee6..b6fbcf6fb2 100644 --- a/src/test/java/io/netty/logging/JdkLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/JdkLoggerFactoryTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class JdkLoggerFactoryTest { @Test diff --git a/src/test/java/io/netty/logging/JdkLoggerTest.java b/common/src/test/java/io/netty/logging/JdkLoggerTest.java similarity index 98% rename from src/test/java/io/netty/logging/JdkLoggerTest.java rename to common/src/test/java/io/netty/logging/JdkLoggerTest.java index 213c963024..4aac0664f1 100644 --- a/src/test/java/io/netty/logging/JdkLoggerTest.java +++ b/common/src/test/java/io/netty/logging/JdkLoggerTest.java @@ -16,16 +16,12 @@ package io.netty.logging; import static org.easymock.EasyMock.*; -import static org.easymock.classextension.EasyMock.*; import static org.junit.Assert.*; import java.util.logging.Level; import org.junit.Test; - -/** - */ public class JdkLoggerTest { private static final Exception e = new Exception(); diff --git a/src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java similarity index 99% rename from src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java index 6265bfe895..66c8532305 100644 --- a/src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/Log4JLoggerFactoryTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class Log4JLoggerFactoryTest { @Test diff --git a/src/test/java/io/netty/logging/Log4JLoggerTest.java b/common/src/test/java/io/netty/logging/Log4JLoggerTest.java similarity index 98% rename from src/test/java/io/netty/logging/Log4JLoggerTest.java rename to common/src/test/java/io/netty/logging/Log4JLoggerTest.java index 933426aaa6..81debf68a5 100644 --- a/src/test/java/io/netty/logging/Log4JLoggerTest.java +++ b/common/src/test/java/io/netty/logging/Log4JLoggerTest.java @@ -16,14 +16,10 @@ package io.netty.logging; import static org.easymock.EasyMock.*; -import static org.easymock.classextension.EasyMock.*; import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class Log4JLoggerTest { private static final Exception e = new Exception(); diff --git a/src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java b/common/src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java similarity index 99% rename from src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java rename to common/src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java index 6b4ec9da51..c365570baa 100644 --- a/src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java +++ b/common/src/test/java/io/netty/logging/Slf4JLoggerFactoryTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class Slf4JLoggerFactoryTest { @Test diff --git a/src/test/java/io/netty/logging/Slf4JLoggerTest.java b/common/src/test/java/io/netty/logging/Slf4JLoggerTest.java similarity index 99% rename from src/test/java/io/netty/logging/Slf4JLoggerTest.java rename to common/src/test/java/io/netty/logging/Slf4JLoggerTest.java index 467623b9bd..2c5d95163e 100644 --- a/src/test/java/io/netty/logging/Slf4JLoggerTest.java +++ b/common/src/test/java/io/netty/logging/Slf4JLoggerTest.java @@ -20,9 +20,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class Slf4JLoggerTest { private static final Exception e = new Exception(); diff --git a/src/test/java/io/netty/util/MapBackedSetTest.java b/common/src/test/java/io/netty/util/MapBackedSetTest.java similarity index 99% rename from src/test/java/io/netty/util/MapBackedSetTest.java rename to common/src/test/java/io/netty/util/MapBackedSetTest.java index 3f35bf97c6..5500063e9f 100644 --- a/src/test/java/io/netty/util/MapBackedSetTest.java +++ b/common/src/test/java/io/netty/util/MapBackedSetTest.java @@ -24,9 +24,6 @@ import java.util.Set; import org.junit.Test; - -/** - */ public class MapBackedSetTest { @Test diff --git a/src/test/java/io/netty/util/internal/ConversionUtilTest.java b/common/src/test/java/io/netty/util/internal/ConversionUtilTest.java similarity index 99% rename from src/test/java/io/netty/util/internal/ConversionUtilTest.java rename to common/src/test/java/io/netty/util/internal/ConversionUtilTest.java index ca2b20faf7..1d393c128a 100644 --- a/src/test/java/io/netty/util/internal/ConversionUtilTest.java +++ b/common/src/test/java/io/netty/util/internal/ConversionUtilTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class ConversionUtilTest { @Test diff --git a/src/test/java/io/netty/util/internal/StringUtilTest.java b/common/src/test/java/io/netty/util/internal/StringUtilTest.java similarity index 100% rename from src/test/java/io/netty/util/internal/StringUtilTest.java rename to common/src/test/java/io/netty/util/internal/StringUtilTest.java diff --git a/example/pom.xml b/example/pom.xml new file mode 100644 index 0000000000..b21e2ea2e3 --- /dev/null +++ b/example/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-example + jar + + Netty/Example + + + + ${project.groupId} + netty-handler + ${project.version} + + + ${project.groupId} + netty-codec-http + ${project.version} + + + ${project.groupId} + netty-transport-sctp + ${project.version} + + + + com.google.protobuf + protobuf-java + + + + diff --git a/src/main/java/io/netty/example/discard/DiscardClient.java b/example/src/main/java/io/netty/example/discard/DiscardClient.java similarity index 87% rename from src/main/java/io/netty/example/discard/DiscardClient.java rename to example/src/main/java/io/netty/example/discard/DiscardClient.java index 308d671000..9ed9c8548c 100644 --- a/src/main/java/io/netty/example/discard/DiscardClient.java +++ b/example/src/main/java/io/netty/example/discard/DiscardClient.java @@ -30,6 +30,41 @@ import io.netty.channel.socket.nio.NioClientSocketChannelFactory; */ public class DiscardClient { + private final String host; + private final int port; + private final int firstMessageSize; + + public DiscardClient(String host, int port, int firstMessageSize) { + this.host = host; + this.port = port; + this.firstMessageSize = firstMessageSize; + } + + public void run() { + // Configure the client. + ClientBootstrap bootstrap = new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + + // Set up the pipeline factory. + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() throws Exception { + return Channels.pipeline( + new DiscardClientHandler(firstMessageSize)); + } + }); + + // Start the connection attempt. + ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); + + // Wait until the connection is closed or the connection attempt fails. + future.getChannel().getCloseFuture().awaitUninterruptibly(); + + // Shut down thread pools to exit. + bootstrap.releaseExternalResources(); + } + public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { @@ -49,28 +84,6 @@ public class DiscardClient { firstMessageSize = 256; } - // Configure the client. - ClientBootstrap bootstrap = new ClientBootstrap( - new NioClientSocketChannelFactory( - Executors.newCachedThreadPool(), - Executors.newCachedThreadPool())); - - // Set up the pipeline factory. - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override - public ChannelPipeline getPipeline() throws Exception { - return Channels.pipeline( - new DiscardClientHandler(firstMessageSize)); - } - }); - - // Start the connection attempt. - ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); - - // Wait until the connection is closed or the connection attempt fails. - future.getChannel().getCloseFuture().awaitUninterruptibly(); - - // Shut down thread pools to exit. - bootstrap.releaseExternalResources(); + new DiscardClient(host, port, firstMessageSize).run(); } } diff --git a/src/main/java/io/netty/example/discard/DiscardClientHandler.java b/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java similarity index 97% rename from src/main/java/io/netty/example/discard/DiscardClientHandler.java rename to example/src/main/java/io/netty/example/discard/DiscardClientHandler.java index e8cb15de24..6d033159fe 100644 --- a/src/main/java/io/netty/example/discard/DiscardClientHandler.java +++ b/example/src/main/java/io/netty/example/discard/DiscardClientHandler.java @@ -38,7 +38,7 @@ public class DiscardClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( DiscardClientHandler.class.getName()); - private long transferredBytes = 0; + private long transferredBytes; private final byte[] content; public DiscardClientHandler(int messageSize) { @@ -84,7 +84,7 @@ public class DiscardClientHandler extends SimpleChannelUpstreamHandler { @Override public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) { - transferredBytes =+e.getWrittenAmount(); + transferredBytes += e.getWrittenAmount(); } @Override diff --git a/src/main/java/io/netty/example/discard/DiscardServer.java b/example/src/main/java/io/netty/example/discard/DiscardServer.java similarity index 82% rename from src/main/java/io/netty/example/discard/DiscardServer.java rename to example/src/main/java/io/netty/example/discard/DiscardServer.java index 67c6373705..978bc9097c 100644 --- a/src/main/java/io/netty/example/discard/DiscardServer.java +++ b/example/src/main/java/io/netty/example/discard/DiscardServer.java @@ -29,7 +29,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class DiscardServer { - public static void main(String[] args) throws Exception { + private final int port; + + public DiscardServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -38,13 +44,22 @@ public class DiscardServer { // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new DiscardServerHandler()); } }); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new DiscardServer(port).run(); } } diff --git a/src/main/java/io/netty/example/discard/DiscardServerHandler.java b/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java similarity index 94% rename from src/main/java/io/netty/example/discard/DiscardServerHandler.java rename to example/src/main/java/io/netty/example/discard/DiscardServerHandler.java index e87f8e398c..19d7336c49 100644 --- a/src/main/java/io/netty/example/discard/DiscardServerHandler.java +++ b/example/src/main/java/io/netty/example/discard/DiscardServerHandler.java @@ -34,7 +34,7 @@ public class DiscardServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( DiscardServerHandler.class.getName()); - private long transferredBytes = 0; + private long transferredBytes; public long getTransferredBytes() { return transferredBytes; @@ -53,7 +53,7 @@ public class DiscardServerHandler extends SimpleChannelUpstreamHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { // Discard received data silently by doing nothing. - transferredBytes += (((ChannelBuffer) e.getMessage()).readableBytes()); + transferredBytes += ((ChannelBuffer) e.getMessage()).readableBytes(); } @Override diff --git a/src/main/java/io/netty/example/echo/EchoClient.java b/example/src/main/java/io/netty/example/echo/EchoClient.java similarity index 88% rename from src/main/java/io/netty/example/echo/EchoClient.java rename to example/src/main/java/io/netty/example/echo/EchoClient.java index 8a9bac8e4f..3b37e9d1b6 100644 --- a/src/main/java/io/netty/example/echo/EchoClient.java +++ b/example/src/main/java/io/netty/example/echo/EchoClient.java @@ -33,6 +33,41 @@ import io.netty.channel.socket.nio.NioClientSocketChannelFactory; */ public class EchoClient { + private final String host; + private final int port; + private final int firstMessageSize; + + public EchoClient(String host, int port, int firstMessageSize) { + this.host = host; + this.port = port; + this.firstMessageSize = firstMessageSize; + } + + public void run() { + // Configure the client. + ClientBootstrap bootstrap = new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + + // Set up the pipeline factory. + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() throws Exception { + return Channels.pipeline( + new EchoClientHandler(firstMessageSize)); + } + }); + + // Start the connection attempt. + ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); + + // Wait until the connection is closed or the connection attempt fails. + future.getChannel().getCloseFuture().awaitUninterruptibly(); + + // Shut down thread pools to exit. + bootstrap.releaseExternalResources(); + } + public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { @@ -52,28 +87,6 @@ public class EchoClient { firstMessageSize = 256; } - // Configure the client. - ClientBootstrap bootstrap = new ClientBootstrap( - new NioClientSocketChannelFactory( - Executors.newCachedThreadPool(), - Executors.newCachedThreadPool())); - - // Set up the pipeline factory. - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override - public ChannelPipeline getPipeline() throws Exception { - return Channels.pipeline( - new EchoClientHandler(firstMessageSize)); - } - }); - - // Start the connection attempt. - ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); - - // Wait until the connection is closed or the connection attempt fails. - future.getChannel().getCloseFuture().awaitUninterruptibly(); - - // Shut down thread pools to exit. - bootstrap.releaseExternalResources(); + new EchoClient(host, port, firstMessageSize).run(); } } diff --git a/src/main/java/io/netty/example/echo/EchoClientHandler.java b/example/src/main/java/io/netty/example/echo/EchoClientHandler.java similarity index 100% rename from src/main/java/io/netty/example/echo/EchoClientHandler.java rename to example/src/main/java/io/netty/example/echo/EchoClientHandler.java diff --git a/src/main/java/io/netty/example/echo/EchoServer.java b/example/src/main/java/io/netty/example/echo/EchoServer.java similarity index 82% rename from src/main/java/io/netty/example/echo/EchoServer.java rename to example/src/main/java/io/netty/example/echo/EchoServer.java index 51c431c234..2dda7bc2a9 100644 --- a/src/main/java/io/netty/example/echo/EchoServer.java +++ b/example/src/main/java/io/netty/example/echo/EchoServer.java @@ -29,7 +29,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class EchoServer { - public static void main(String[] args) throws Exception { + private final int port; + + public EchoServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -38,13 +44,22 @@ public class EchoServer { // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new EchoServerHandler()); } }); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new EchoServer(port).run(); } } diff --git a/src/main/java/io/netty/example/echo/EchoServerHandler.java b/example/src/main/java/io/netty/example/echo/EchoServerHandler.java similarity index 100% rename from src/main/java/io/netty/example/echo/EchoServerHandler.java rename to example/src/main/java/io/netty/example/echo/EchoServerHandler.java diff --git a/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java b/example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java similarity index 100% rename from src/main/java/io/netty/example/factorial/BigIntegerDecoder.java rename to example/src/main/java/io/netty/example/factorial/BigIntegerDecoder.java diff --git a/src/main/java/io/netty/example/factorial/FactorialClient.java b/example/src/main/java/io/netty/example/factorial/FactorialClient.java similarity index 89% rename from src/main/java/io/netty/example/factorial/FactorialClient.java rename to example/src/main/java/io/netty/example/factorial/FactorialClient.java index 246916fed5..b35c5278e9 100644 --- a/src/main/java/io/netty/example/factorial/FactorialClient.java +++ b/example/src/main/java/io/netty/example/factorial/FactorialClient.java @@ -29,23 +29,17 @@ import io.netty.channel.socket.nio.NioClientSocketChannelFactory; */ public class FactorialClient { - public static void main(String[] args) throws Exception { - // Print usage if no argument is specified. - if (args.length != 3) { - System.err.println( - "Usage: " + FactorialClient.class.getSimpleName() + - " "); - return; - } + private final String host; + private final int port; + private final int count; - // Parse options. - String host = args[0]; - int port = Integer.parseInt(args[1]); - int count = Integer.parseInt(args[2]); - if (count <= 0) { - throw new IllegalArgumentException("count must be a positive integer."); - } + public FactorialClient(String host, int port, int count) { + this.host = host; + this.port = port; + this.count = count; + } + public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( @@ -73,4 +67,24 @@ public class FactorialClient { // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + // Print usage if no argument is specified. + if (args.length != 3) { + System.err.println( + "Usage: " + FactorialClient.class.getSimpleName() + + " "); + return; + } + + // Parse options. + String host = args[0]; + int port = Integer.parseInt(args[1]); + int count = Integer.parseInt(args[2]); + if (count <= 0) { + throw new IllegalArgumentException("count must be a positive integer."); + } + + new FactorialClient(host, port, count).run(); + } } diff --git a/src/main/java/io/netty/example/factorial/FactorialClientHandler.java b/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java similarity index 99% rename from src/main/java/io/netty/example/factorial/FactorialClientHandler.java rename to example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java index f6095bd677..72a98ad781 100644 --- a/src/main/java/io/netty/example/factorial/FactorialClientHandler.java +++ b/example/src/main/java/io/netty/example/factorial/FactorialClientHandler.java @@ -45,7 +45,7 @@ public class FactorialClientHandler extends SimpleChannelUpstreamHandler { // Stateful properties private int i = 1; - private int receivedMessages = 0; + private int receivedMessages; private final int count; final BlockingQueue answer = new LinkedBlockingQueue(); diff --git a/src/main/java/io/netty/example/factorial/FactorialClientPipelineFactory.java b/example/src/main/java/io/netty/example/factorial/FactorialClientPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/factorial/FactorialClientPipelineFactory.java rename to example/src/main/java/io/netty/example/factorial/FactorialClientPipelineFactory.java diff --git a/src/main/java/io/netty/example/factorial/FactorialServer.java b/example/src/main/java/io/netty/example/factorial/FactorialServer.java similarity index 80% rename from src/main/java/io/netty/example/factorial/FactorialServer.java rename to example/src/main/java/io/netty/example/factorial/FactorialServer.java index f102191b96..c8e4290958 100644 --- a/src/main/java/io/netty/example/factorial/FactorialServer.java +++ b/example/src/main/java/io/netty/example/factorial/FactorialServer.java @@ -27,7 +27,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class FactorialServer { - public static void main(String[] args) throws Exception { + private final int port; + + public FactorialServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -38,6 +44,16 @@ public class FactorialServer { bootstrap.setPipelineFactory(new FactorialServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new FactorialServer(port).run(); } } diff --git a/src/main/java/io/netty/example/factorial/FactorialServerHandler.java b/example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java similarity index 100% rename from src/main/java/io/netty/example/factorial/FactorialServerHandler.java rename to example/src/main/java/io/netty/example/factorial/FactorialServerHandler.java diff --git a/src/main/java/io/netty/example/factorial/FactorialServerPipelineFactory.java b/example/src/main/java/io/netty/example/factorial/FactorialServerPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/factorial/FactorialServerPipelineFactory.java rename to example/src/main/java/io/netty/example/factorial/FactorialServerPipelineFactory.java diff --git a/src/main/java/io/netty/example/factorial/NumberEncoder.java b/example/src/main/java/io/netty/example/factorial/NumberEncoder.java similarity index 100% rename from src/main/java/io/netty/example/factorial/NumberEncoder.java rename to example/src/main/java/io/netty/example/factorial/NumberEncoder.java diff --git a/src/main/java/io/netty/example/http/file/HttpStaticFileServer.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServer.java similarity index 78% rename from src/main/java/io/netty/example/http/file/HttpStaticFileServer.java rename to example/src/main/java/io/netty/example/http/file/HttpStaticFileServer.java index 78cf58523a..9cb73d72cd 100644 --- a/src/main/java/io/netty/example/http/file/HttpStaticFileServer.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServer.java @@ -21,10 +21,15 @@ import java.util.concurrent.Executors; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class HttpStaticFileServer { - public static void main(String[] args) { + + private final int port; + + public HttpStaticFileServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -35,6 +40,16 @@ public class HttpStaticFileServer { bootstrap.setPipelineFactory(new HttpStaticFileServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new HttpStaticFileServer(port).run(); } } diff --git a/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java similarity index 99% rename from src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java rename to example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java index 037e488b3f..29df997778 100644 --- a/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerHandler.java @@ -134,8 +134,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler { // Cache Validation String ifModifiedSince = request.getHeader(HttpHeaders.Names.IF_MODIFIED_SINCE); - if (ifModifiedSince != null && !ifModifiedSince.equals("")) - { + if (ifModifiedSince != null && !ifModifiedSince.equals("")) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); diff --git a/src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java similarity index 99% rename from src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java index 566e622ff9..71791005b5 100644 --- a/src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/file/HttpStaticFileServerPipelineFactory.java @@ -24,8 +24,6 @@ import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.stream.ChunkedWriteHandler; -/** - */ public class HttpStaticFileServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { diff --git a/src/main/java/io/netty/example/http/snoop/HttpClient.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClient.java similarity index 90% rename from src/main/java/io/netty/example/http/snoop/HttpClient.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopClient.java index 1a665e02c5..436da5b6d8 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpClient.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClient.java @@ -32,19 +32,17 @@ import io.netty.handler.codec.http.HttpVersion; /** * A simple HTTP client that prints out the content of the HTTP response to - * {@link System#out} to test {@link HttpServer}. + * {@link System#out} to test {@link HttpSnoopServer}. */ -public class HttpClient { +public class HttpSnoopClient { - public static void main(String[] args) throws Exception { - if (args.length != 1) { - System.err.println( - "Usage: " + HttpClient.class.getSimpleName() + - " "); - return; - } + private final URI uri; - URI uri = new URI(args[0]); + public HttpSnoopClient(URI uri) { + this.uri = uri; + } + + public void run() { String scheme = uri.getScheme() == null? "http" : uri.getScheme(); String host = uri.getHost() == null? "localhost" : uri.getHost(); int port = uri.getPort(); @@ -70,7 +68,7 @@ public class HttpClient { Executors.newCachedThreadPool())); // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new HttpClientPipelineFactory(ssl)); + bootstrap.setPipelineFactory(new HttpSnoopClientPipelineFactory(ssl)); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); @@ -105,4 +103,16 @@ public class HttpClient { // Shut down executor threads to exit. bootstrap.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + System.err.println( + "Usage: " + HttpSnoopClient.class.getSimpleName() + + " "); + return; + } + + URI uri = new URI(args[0]); + new HttpSnoopClient(uri).run(); + } } diff --git a/src/main/java/io/netty/example/http/snoop/HttpResponseHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java similarity index 97% rename from src/main/java/io/netty/example/http/snoop/HttpResponseHandler.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java index 1feef4fa0f..0e5d83e703 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpResponseHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientHandler.java @@ -23,9 +23,7 @@ import io.netty.handler.codec.http.HttpChunk; import io.netty.handler.codec.http.HttpResponse; import io.netty.util.CharsetUtil; -/** - */ -public class HttpResponseHandler extends SimpleChannelUpstreamHandler { +public class HttpSnoopClientHandler extends SimpleChannelUpstreamHandler { private boolean readingChunks; diff --git a/src/main/java/io/netty/example/http/snoop/HttpClientPipelineFactory.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientPipelineFactory.java similarity index 91% rename from src/main/java/io/netty/example/http/snoop/HttpClientPipelineFactory.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientPipelineFactory.java index eb98ed5f53..7013659ef4 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpClientPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopClientPipelineFactory.java @@ -28,13 +28,11 @@ import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslHandler; import io.netty.logging.InternalLogLevel; -/** - */ -public class HttpClientPipelineFactory implements ChannelPipelineFactory { +public class HttpSnoopClientPipelineFactory implements ChannelPipelineFactory { private final boolean ssl; - public HttpClientPipelineFactory(boolean ssl) { + public HttpSnoopClientPipelineFactory(boolean ssl) { this.ssl = ssl; } @@ -61,7 +59,7 @@ public class HttpClientPipelineFactory implements ChannelPipelineFactory { // Uncomment the following line if you don't want to handle HttpChunks. //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576)); - pipeline.addLast("handler", new HttpResponseHandler()); + pipeline.addLast("handler", new HttpSnoopClientHandler()); return pipeline; } } diff --git a/src/main/java/io/netty/example/http/snoop/HttpServer.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServer.java similarity index 74% rename from src/main/java/io/netty/example/http/snoop/HttpServer.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopServer.java index e3595b7234..610c051622 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpServer.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServer.java @@ -25,8 +25,15 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; * An HTTP server that sends back the content of the received HTTP request * in a pretty plaintext form. */ -public class HttpServer { - public static void main(String[] args) { +public class HttpSnoopServer { + + private final int port; + + public HttpSnoopServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -34,9 +41,19 @@ public class HttpServer { Executors.newCachedThreadPool())); // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new HttpServerPipelineFactory()); + bootstrap.setPipelineFactory(new HttpSnoopServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new HttpSnoopServer(port).run(); } } diff --git a/src/main/java/io/netty/example/http/snoop/HttpRequestHandler.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java similarity index 98% rename from src/main/java/io/netty/example/http/snoop/HttpRequestHandler.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java index bbde904733..512fdd7cda 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpRequestHandler.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerHandler.java @@ -44,9 +44,7 @@ import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.CharsetUtil; -/** - */ -public class HttpRequestHandler extends SimpleChannelUpstreamHandler { +public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler { private HttpRequest request; private boolean readingChunks; @@ -140,7 +138,7 @@ public class HttpRequestHandler extends SimpleChannelUpstreamHandler { if (cookieString != null) { CookieDecoder cookieDecoder = new CookieDecoder(); Set cookies = cookieDecoder.decode(cookieString); - if(!cookies.isEmpty()) { + if (!cookies.isEmpty()) { // Reset the cookies if necessary. CookieEncoder cookieEncoder = new CookieEncoder(true); for (Cookie cookie : cookies) { diff --git a/src/main/java/io/netty/example/http/snoop/HttpServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerPipelineFactory.java similarity index 93% rename from src/main/java/io/netty/example/http/snoop/HttpServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerPipelineFactory.java index bbeb1424a2..e8241e96ce 100644 --- a/src/main/java/io/netty/example/http/snoop/HttpServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/snoop/HttpSnoopServerPipelineFactory.java @@ -25,9 +25,7 @@ import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.logging.LoggingHandler; import io.netty.logging.InternalLogLevel; -/** - */ -public class HttpServerPipelineFactory implements ChannelPipelineFactory { +public class HttpSnoopServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. @@ -45,7 +43,7 @@ public class HttpServerPipelineFactory implements ChannelPipelineFactory { pipeline.addLast("encoder", new HttpResponseEncoder()); // Remove the following line if you don't want automatic content compression. pipeline.addLast("deflater", new HttpContentCompressor()); - pipeline.addLast("handler", new HttpRequestHandler()); + pipeline.addLast("handler", new HttpSnoopServerHandler()); return pipeline; } } diff --git a/src/main/java/io/netty/example/http/upload/HttpClient.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadClient.java similarity index 67% rename from src/main/java/io/netty/example/http/upload/HttpClient.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadClient.java index b893113bef..13423f977b 100644 --- a/src/main/java/io/netty/example/http/upload/HttpClient.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadClient.java @@ -27,49 +27,49 @@ import io.netty.bootstrap.ClientBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; -import io.netty.handler.codec.http.QueryStringEncoder; import io.netty.handler.codec.http.CookieEncoder; import io.netty.handler.codec.http.DefaultHttpDataFactory; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.DiskAttribute; import io.netty.handler.codec.http.DiskFileUpload; -import io.netty.handler.codec.http.InterfaceHttpData; -import io.netty.handler.codec.http.HttpPostRequestEncoder; import io.netty.handler.codec.http.HttpDataFactory; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpPostRequestEncoder; +import io.netty.handler.codec.http.HttpPostRequestEncoder.ErrorDataEncoderException; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.HttpPostRequestEncoder.ErrorDataEncoderException; +import io.netty.handler.codec.http.InterfaceHttpData; +import io.netty.handler.codec.http.QueryStringEncoder; /** */ -public class HttpClient { +public class HttpUploadClient { + + private final String baseUri; + private final String filePath; + + public HttpUploadClient(String baseUri, String filePath) { + this.baseUri = baseUri; + this.filePath = filePath; + } - public static void main(String[] args) { - if (args.length != 2) { - System.err.println( - "Usage: " + HttpClient.class.getSimpleName() + - " baseURI Filepath"); - return; - } - - String baseURI = args[0]; + public void run() { String postSimple, postFile, get; - if (baseURI.endsWith("/")) { - postSimple = baseURI+"formpost"; - postFile = baseURI+"formpostmultipart"; - get = baseURI+"formget"; + if (baseUri.endsWith("/")) { + postSimple = baseUri + "formpost"; + postFile = baseUri + "formpostmultipart"; + get = baseUri + "formget"; } else { - postSimple = baseURI+"/formpost"; - postFile = baseURI+"/formpostmultipart"; - get = baseURI+"/formget"; + postSimple = baseUri + "/formpost"; + postFile = baseUri + "/formpostmultipart"; + get = baseUri + "/formget"; } URI uriSimple; try { uriSimple = new URI(postSimple); } catch (URISyntaxException e) { - System.err.println("Error: "+e.getMessage()); + System.err.println("Error: " + e.getMessage()); return; } String scheme = uriSimple.getScheme() == null? "http" : uriSimple.getScheme(); @@ -94,10 +94,10 @@ public class HttpClient { try { uriFile = new URI(postFile); } catch (URISyntaxException e) { - System.err.println("Error: "+e.getMessage()); + System.err.println("Error: " + e.getMessage()); return; } - File file = new File(args[1]); + File file = new File(filePath); if (! file.canRead()) { System.err.println("A correct path is needed"); return; @@ -110,7 +110,7 @@ public class HttpClient { Executors.newCachedThreadPool())); // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new HttpClientPipelineFactory(ssl)); + bootstrap.setPipelineFactory(new HttpUploadClientPipelineFactory(ssl)); // setup the factory: here using a mixed memory/disk based on size threshold HttpDataFactory factory = new DefaultHttpDataFactory( @@ -121,7 +121,7 @@ public class HttpClient { DiskAttribute.baseDirectory = null; // system temp directory // Simple Get form: no factory used (not usable) - List> headers = + List> headers = formget(bootstrap, host, port, get, uriSimple); if (headers == null) { factory.cleanAllHttpDatas(); @@ -135,7 +135,7 @@ public class HttpClient { return; } // Multipart Post form: factory used - formpostmultipart(bootstrap, host, port, uriFile, file, factory, headers, bodylist); + formpostmultipart(bootstrap, host, port, uriFile, factory, headers, bodylist); // Shut down executor threads to exit. bootstrap.releaseExternalResources(); @@ -148,7 +148,7 @@ public class HttpClient { * due to limitation on request size). * @return the list of headers that will be used in every example after **/ - private static List> formget(ClientBootstrap bootstrap, String host, int port, String get, + private static List> formget(ClientBootstrap bootstrap, String host, int port, String get, URI uriSimple) { // XXX /formget // No use of HttpPostRequestEncoder since not a POST @@ -165,19 +165,19 @@ public class HttpClient { // Prepare the HTTP request. QueryStringEncoder encoder = new QueryStringEncoder(get); // add Form attribute - encoder.addParam("getform","GET"); - encoder.addParam("info","first value"); - encoder.addParam("secondinfo","secondvalue ���&"); + encoder.addParam("getform", "GET"); + encoder.addParam("info", "first value"); + encoder.addParam("secondinfo", "secondvalue ���&"); // not the big one since it is not compatible with GET size // encoder.addParam("thirdinfo", textArea); encoder.addParam("thirdinfo", "third value\r\ntest second line\r\n\r\nnew line\r\n"); - encoder.addParam("Send","Send"); + encoder.addParam("Send", "Send"); URI uriGet; try { uriGet = new URI(encoder.toString()); } catch (URISyntaxException e) { - System.err.println("Error: "+e.getMessage()); + System.err.println("Error: " + e.getMessage()); bootstrap.releaseExternalResources(); return null; } @@ -186,7 +186,7 @@ public class HttpClient { HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString()); request.setHeader(HttpHeaders.Names.HOST, host); request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); - request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP+","+ + request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE); request.setHeader(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); @@ -204,7 +204,7 @@ public class HttpClient { httpCookieEncoder.addCookie("another-cookie", "bar"); request.setHeader(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode()); - List> headers = request.getHeaders(); + List> headers = request.getHeaders(); // send request channel.write(request); @@ -216,19 +216,13 @@ public class HttpClient { /** * Standard post without multipart but already support on Factory (memory management) - * @param bootstrap - * @param host - * @param port - * @param uriSimple - * @param file - * @param factory - * @param headers + * * @return the list of HttpData object (attribute and file) to be reused on next post */ private static List formpost(ClientBootstrap bootstrap, String host, int port, URI uriSimple, File file, HttpDataFactory factory, - List> headers) { + List> headers) { // XXX /formpost // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); @@ -264,12 +258,12 @@ public class HttpClient { // add Form attribute try { - bodyRequestEncoder.addBodyAttribute("getform","POST"); - bodyRequestEncoder.addBodyAttribute("info","first value"); - bodyRequestEncoder.addBodyAttribute("secondinfo","secondvalue ���&"); + bodyRequestEncoder.addBodyAttribute("getform", "POST"); + bodyRequestEncoder.addBodyAttribute("info", "first value"); + bodyRequestEncoder.addBodyAttribute("secondinfo", "secondvalue ���&"); bodyRequestEncoder.addBodyAttribute("thirdinfo", textArea); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); - bodyRequestEncoder.addBodyAttribute("Send","Send"); + bodyRequestEncoder.addBodyAttribute("Send", "Send"); } catch (NullPointerException e) { // should not be since not null args e.printStackTrace(); @@ -311,18 +305,10 @@ public class HttpClient { /** * Multipart example - * @param bootstrap - * @param host - * @param port - * @param uriFile - * @param file - * @param factory - * @param headers - * @param bodylist */ private static void formpostmultipart(ClientBootstrap bootstrap, String host, int port, - URI uriFile, File file, HttpDataFactory factory, - List> headers, List bodylist) { + URI uriFile, HttpDataFactory factory, + List> headers, List bodylist) { // XXX /formpostmultipart // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); @@ -390,600 +376,607 @@ public class HttpClient { channel.getCloseFuture().awaitUninterruptibly(); } + public static void main(String[] args) { + if (args.length != 2) { + System.err.println( + "Usage: " + HttpUploadClient.class.getSimpleName() + + " baseURI filePath"); + return; + } + String baseUri = args[0]; + String filePath = args[1]; - - - - + new HttpUploadClient(baseUri, filePath).run(); + } // use to simulate a big TEXTAREA field in a form private static final String textArea = - "lkjlkjlKJLKJLKJLKJLJlkj lklkj\r\n\r\nLKJJJJJJJJKKKKKKKKKKKKKKK ����&\r\n\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ - "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"+ + "lkjlkjlKJLKJLKJLKJLJlkj lklkj\r\n\r\nLKJJJJJJJJKKKKKKKKKKKKKKK ����&\r\n\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n" + "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"; } diff --git a/src/main/java/io/netty/example/http/upload/HttpResponseHandler.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java similarity index 97% rename from src/main/java/io/netty/example/http/upload/HttpResponseHandler.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java index aecfa869ab..6ad6fe52f0 100644 --- a/src/main/java/io/netty/example/http/upload/HttpResponseHandler.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientHandler.java @@ -24,9 +24,7 @@ import io.netty.handler.codec.http.HttpChunk; import io.netty.handler.codec.http.HttpResponse; import io.netty.util.CharsetUtil; -/** - */ -public class HttpResponseHandler extends SimpleChannelUpstreamHandler { +public class HttpUploadClientHandler extends SimpleChannelUpstreamHandler { private volatile boolean readingChunks; diff --git a/src/main/java/io/netty/example/http/upload/HttpClientPipelineFactory.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientPipelineFactory.java similarity index 90% rename from src/main/java/io/netty/example/http/upload/HttpClientPipelineFactory.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadClientPipelineFactory.java index b7db7f8334..149d8c622e 100644 --- a/src/main/java/io/netty/example/http/upload/HttpClientPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadClientPipelineFactory.java @@ -27,12 +27,10 @@ import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; -/** - */ -public class HttpClientPipelineFactory implements ChannelPipelineFactory { +public class HttpUploadClientPipelineFactory implements ChannelPipelineFactory { private final boolean ssl; - public HttpClientPipelineFactory(boolean ssl) { + public HttpUploadClientPipelineFactory(boolean ssl) { this.ssl = ssl; } @@ -58,7 +56,7 @@ public class HttpClientPipelineFactory implements ChannelPipelineFactory { // to be used since huge file transfer pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); - pipeline.addLast("handler", new HttpResponseHandler()); + pipeline.addLast("handler", new HttpUploadClientHandler()); return pipeline; } } diff --git a/src/main/java/io/netty/example/http/upload/HttpServer.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadServer.java similarity index 71% rename from src/main/java/io/netty/example/http/upload/HttpServer.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadServer.java index 00f5fdf6c6..d5bf1194e6 100644 --- a/src/main/java/io/netty/example/http/upload/HttpServer.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadServer.java @@ -21,10 +21,15 @@ import java.util.concurrent.Executors; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ -public class HttpServer { - public static void main(String[] args) { +public class HttpUploadServer { + + private final int port; + + public HttpUploadServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -32,9 +37,19 @@ public class HttpServer { Executors.newCachedThreadPool())); // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new HttpServerPipelineFactory()); + bootstrap.setPipelineFactory(new HttpUploadServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new HttpUploadServer(port).run(); } } diff --git a/src/main/java/io/netty/example/http/upload/HttpRequestHandler.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java similarity index 99% rename from src/main/java/io/netty/example/http/upload/HttpRequestHandler.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java index 974be7f05d..e6c4974e56 100644 --- a/src/main/java/io/netty/example/http/upload/HttpRequestHandler.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java @@ -60,20 +60,18 @@ import io.netty.handler.codec.http.InterfaceHttpData.HttpDataType; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.CharsetUtil; -/** - */ -public class HttpRequestHandler extends SimpleChannelUpstreamHandler { +public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler { private volatile HttpRequest request; - private volatile boolean readingChunks = false; + private volatile boolean readingChunks; private final StringBuilder responseContent = new StringBuilder(); private static final HttpDataFactory factory = new DefaultHttpDataFactory( DefaultHttpDataFactory.MINSIZE); // Disk if size exceed MINSIZE - private HttpPostRequestDecoder decoder = null; + private HttpPostRequestDecoder decoder; static { DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file // on exit (in normal diff --git a/src/main/java/io/netty/example/http/upload/HttpServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerPipelineFactory.java similarity index 92% rename from src/main/java/io/netty/example/http/upload/HttpServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/upload/HttpUploadServerPipelineFactory.java index b330298636..edb1a5a802 100644 --- a/src/main/java/io/netty/example/http/upload/HttpServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/upload/HttpUploadServerPipelineFactory.java @@ -23,9 +23,7 @@ import io.netty.handler.codec.http.HttpContentCompressor; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; -/** - */ -public class HttpServerPipelineFactory implements ChannelPipelineFactory { +public class HttpUploadServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { // Create a default pipeline implementation. @@ -43,7 +41,7 @@ public class HttpServerPipelineFactory implements ChannelPipelineFactory { // Remove the following line if you don't want automatic content compression. pipeline.addLast("deflater", new HttpContentCompressor()); - pipeline.addLast("handler", new HttpRequestHandler()); + pipeline.addLast("handler", new HttpUploadServerHandler()); return pipeline; } } diff --git a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServer.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServer.java similarity index 50% rename from src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServer.java rename to example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServer.java index 25251152ad..2f2f5bab4e 100644 --- a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServer.java +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServer.java @@ -25,28 +25,40 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; /** - * A Web Socket echo server for running the autobahn - * test suite + * A Web Socket echo server for running the autobahn test + * suite */ -public class WebSocketServer { - public static void main(String[] args) { - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINE); - Logger.getLogger("").addHandler(ch); - Logger.getLogger("").setLevel(Level.FINE); - - // Configure the server. - ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( - Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); - - //bootstrap.setOption("child.tcpNoDelay", true); - - // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); +public class AutobahnServer { - // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(9000)); - - System.out.println("Web Socket Server started on localhost:9000."); - } + private final int port; + + public AutobahnServer(int port) { + this.port = port; + } + + public void run() { + // Configure the server. + ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); + + // bootstrap.setOption("child.tcpNoDelay", true); + + // Set up the event pipeline factory. + bootstrap.setPipelineFactory(new AutobahnServerPipelineFactory()); + + // Bind and start to accept incoming connections. + bootstrap.bind(new InetSocketAddress(port)); + + System.out.println("Web Socket Server started at port " + port); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 9000; + } + new AutobahnServer(port).run(); + } } diff --git a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java new file mode 100644 index 0000000000..83d54025bc --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java @@ -0,0 +1,133 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.autobahn; + +import static io.netty.handler.codec.http.HttpHeaders.*; +import static io.netty.handler.codec.http.HttpMethod.*; +import static io.netty.handler.codec.http.HttpResponseStatus.*; +import static io.netty.handler.codec.http.HttpVersion.*; + +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.CharsetUtil; + +/** + * Handles handshakes and messages + */ +public class AutobahnServerHandler extends SimpleChannelUpstreamHandler { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(AutobahnServerHandler.class); + + private WebSocketServerHandshaker handshaker; + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + Object msg = e.getMessage(); + if (msg instanceof HttpRequest) { + handleHttpRequest(ctx, (HttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } + } + + private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { + // Allow only GET methods. + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); + return; + } + + // Handshake + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + this.getWebSocketLocation(req), null, false); + this.handshaker = wsFactory.newHandshaker(req); + if (this.handshaker == null) { + wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); + } else { + this.handshaker.handshake(ctx.getChannel(), req); + } + } + + private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { + logger.debug(String + .format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName())); + + if (frame instanceof CloseWebSocketFrame) { + this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); + } else if (frame instanceof PingWebSocketFrame) { + ctx.getChannel().write( + new PongWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); + } else if (frame instanceof TextWebSocketFrame) { + // String text = ((TextWebSocketFrame) frame).getText(); + ctx.getChannel().write( + new TextWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); + } else if (frame instanceof BinaryWebSocketFrame) { + ctx.getChannel().write( + new BinaryWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); + } else if (frame instanceof ContinuationWebSocketFrame) { + ctx.getChannel().write( + new ContinuationWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); + } else if (frame instanceof PongWebSocketFrame) { + // Ignore + } else { + throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() + .getName())); + } + } + + private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { + // Generate an error page if response status code is not OK (200). + if (res.getStatus().getCode() != 200) { + res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); + setContentLength(res, res.getContent().readableBytes()); + } + + // Send the response and close the connection if necessary. + ChannelFuture f = ctx.getChannel().write(res); + if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { + f.addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + e.getCause().printStackTrace(); + e.getChannel().close(); + } + + private String getWebSocketLocation(HttpRequest req) { + return "ws://" + req.getHeader(HttpHeaders.Names.HOST); + } +} diff --git a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerPipelineFactory.java similarity index 64% rename from src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerPipelineFactory.java index ff2ffa6ebf..44eea6cd97 100644 --- a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerPipelineFactory.java @@ -23,17 +23,15 @@ import io.netty.handler.codec.http.HttpChunkAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; -/** - */ -public class WebSocketServerPipelineFactory implements ChannelPipelineFactory { - @Override - public ChannelPipeline getPipeline() throws Exception { - // Create a default pipeline implementation. - ChannelPipeline pipeline = pipeline(); - pipeline.addLast("decoder", new HttpRequestDecoder()); - pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); - pipeline.addLast("encoder", new HttpResponseEncoder()); - pipeline.addLast("handler", new WebSocketServerHandler()); - return pipeline; - } +public class AutobahnServerPipelineFactory implements ChannelPipelineFactory { + @Override + public ChannelPipeline getPipeline() throws Exception { + // Create a default pipeline implementation. + ChannelPipeline pipeline = pipeline(); + pipeline.addLast("decoder", new HttpRequestDecoder()); + pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); + pipeline.addLast("encoder", new HttpResponseEncoder()); + pipeline.addLast("handler", new AutobahnServerHandler()); + return pipeline; + } } diff --git a/src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java similarity index 87% rename from src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java rename to example/src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java index f78f6ae5ef..892442c725 100644 --- a/src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java +++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/package-info.java @@ -36,7 +36,7 @@ * *

08. Go to test suite directory: cd testsuite/websockets * - *

09. Edit fuzzing_clinet_spec.json and set the version to 10 or 17. + *

09. Edit fuzzing_clinet_spec.json and set the hybi specification version to 10 or 17 (RFC 6455). * * { * "options": {"failByDrop": false}, @@ -47,11 +47,13 @@ * } * * - *

10. Run the test python fuzzing_client.py. Note that the actual test case python code is + *

10. Run AutobahnServer in this package + * + *

11. Run the test python fuzzing_client.py. Note that the actual test case python code is * located in /usr/local/lib/python2.6/dist-packages/autobahn-0.4.3-py2.6.egg/autobahn/cases * and not in the checked out git repository. * - *

11. See the results in reports/servers/index.html + *

12. See the results in reports/servers/index.html */ package io.netty.example.http.websocketx.autobahn; diff --git a/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java new file mode 100644 index 0000000000..9dc282eb52 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java @@ -0,0 +1,153 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +//The MIT License +// +//Copyright (c) 2009 Carl Bystršm +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in +//all copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//THE SOFTWARE. +package io.netty.example.http.websocketx.client; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.Executors; + +import io.netty.bootstrap.ClientBootstrap; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPipelineFactory; +import io.netty.channel.Channels; +import io.netty.channel.socket.nio.NioClientSocketChannelFactory; +import io.netty.handler.codec.http.HttpRequestEncoder; +import io.netty.handler.codec.http.HttpResponseDecoder; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; +import io.netty.handler.codec.http.websocketx.WebSocketVersion; + +public class WebSocketClient { + + private final URI uri; + + public WebSocketClient(URI uri) { + this.uri = uri; + } + + public void run() throws Exception { + ClientBootstrap bootstrap = + new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + + Channel ch = null; + + try { + String protocol = uri.getScheme(); + if (!protocol.equals("ws")) { + throw new IllegalArgumentException("Unsupported protocol: " + protocol); + } + + HashMap customHeaders = new HashMap(); + customHeaders.put("MyHeader", "MyValue"); + + // Connect with V13 (RFC 6455). You can change it to V08 or V00. + // If you change it to V00, ping is not supported and remember to change + // HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline. + final WebSocketClientHandshaker handshaker = + new WebSocketClientHandshakerFactory().newHandshaker( + uri, WebSocketVersion.V13, null, false, customHeaders); + + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = Channels.pipeline(); + + // If you wish to support HyBi V00, you need to use + // WebSocketHttpResponseDecoder instead for + // HttpResponseDecoder. + pipeline.addLast("decoder", new HttpResponseDecoder()); + + pipeline.addLast("encoder", new HttpRequestEncoder()); + pipeline.addLast("ws-handler", new WebSocketClientHandler(handshaker)); + return pipeline; + } + }); + + // Connect + System.out.println("WebSocket Client connecting"); + ChannelFuture future = + bootstrap.connect( + new InetSocketAddress(uri.getHost(), uri.getPort())); + future.awaitUninterruptibly().rethrowIfFailed(); + + ch = future.getChannel(); + handshaker.handshake(ch).awaitUninterruptibly().rethrowIfFailed(); + + // Send 10 messages and wait for responses + System.out.println("WebSocket Client sending message"); + for (int i = 0; i < 10; i++) { + ch.write(new TextWebSocketFrame("Message #" + i)); + } + + // Ping + System.out.println("WebSocket Client sending ping"); + ch.write(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6}))); + + // Close + System.out.println("WebSocket Client sending close"); + ch.write(new CloseWebSocketFrame()); + + // WebSocketClientHandler will close the connection when the server + // responds to the CloseWebSocketFrame. + ch.getCloseFuture().awaitUninterruptibly(); + } finally { + if (ch != null) { + ch.close(); + } + bootstrap.releaseExternalResources(); + } + } + + public static void main(String[] args) throws Exception { + URI uri; + if (args.length > 0) { + uri = new URI(args[0]); + } else { + uri = new URI("ws://localhost:8080/websocket"); + } + new WebSocketClient(uri).run(); + } +} diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java similarity index 51% rename from src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java rename to example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java index 3649911ace..2c0be64576 100644 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java +++ b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ //The MIT License // //Copyright (c) 2009 Carl Bystršm @@ -22,103 +37,64 @@ package io.netty.example.http.websocketx.client; -import java.net.InetSocketAddress; -import java.net.URI; - -import io.netty.bootstrap.ClientBootstrap; import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelStateEvent; import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; -import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketSpecificationVersion; import io.netty.util.CharsetUtil; -/** - * Copied from https://github.com/cgbystrom/netty-tools - * - * Handles socket communication for a connected WebSocket client Not intended for end-users. Please use - * {@link WebSocketClient} or {@link WebSocketCallback} for controlling your client. - */ -public class WebSocketClientHandler extends SimpleChannelUpstreamHandler implements WebSocketClient { +public class WebSocketClientHandler extends SimpleChannelUpstreamHandler { - private final ClientBootstrap bootstrap; - private URI url; - private final WebSocketCallback callback; - private Channel channel; - private WebSocketClientHandshaker handshaker = null; - private final WebSocketSpecificationVersion version; + private final WebSocketClientHandshaker handshaker; - public WebSocketClientHandler(ClientBootstrap bootstrap, URI url, WebSocketSpecificationVersion version, WebSocketCallback callback) { - this.bootstrap = bootstrap; - this.url = url; - this.version = version; - this.callback = callback; - } - - @Override - public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - channel = e.getChannel(); - this.handshaker = new WebSocketClientHandshakerFactory().newHandshaker(url, version, null, false); - handshaker.performOpeningHandshake(channel); + public WebSocketClientHandler(WebSocketClientHandshaker handshaker) { + this.handshaker = handshaker; } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - callback.onDisconnect(this); + System.out.println("WebSocket Client disconnected!"); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - if (!handshaker.isOpeningHandshakeCompleted()) { - handshaker.performClosingHandshake(ctx.getChannel(), (HttpResponse) e.getMessage()); - callback.onConnect(this); + Channel ch = ctx.getChannel(); + if (!handshaker.isHandshakeComplete()) { + handshaker.finishHandshake(ch, (HttpResponse) e.getMessage()); + System.out.println("WebSocket Client connected!"); return; } if (e.getMessage() instanceof HttpResponse) { HttpResponse response = (HttpResponse) e.getMessage(); - throw new WebSocketException("Unexpected HttpResponse (status=" + response.getStatus() + ", content=" + throw new Exception("Unexpected HttpResponse (status=" + response.getStatus() + ", content=" + response.getContent().toString(CharsetUtil.UTF_8) + ")"); } WebSocketFrame frame = (WebSocketFrame) e.getMessage(); - callback.onMessage(this, frame); + if (frame instanceof TextWebSocketFrame) { + TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; + System.out.println("WebSocket Client received message: " + textFrame.getText()); + } else if (frame instanceof PongWebSocketFrame) { + System.out.println("WebSocket Client received pong"); + } else if (frame instanceof CloseWebSocketFrame) { + System.out.println("WebSocket Client received closing"); + ch.close(); + } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { final Throwable t = e.getCause(); - callback.onError(t); + t.printStackTrace(); e.getChannel().close(); } - - @Override - public ChannelFuture connect() { - return bootstrap.connect(new InetSocketAddress(url.getHost(), url.getPort())); - } - - @Override - public ChannelFuture disconnect() { - return channel.close(); - } - - @Override - public ChannelFuture send(WebSocketFrame frame) { - return channel.write(frame); - } - - public URI getUrl() { - return url; - } - - public void setUrl(URI url) { - this.url = url; - } } diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java similarity index 93% rename from src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java rename to example/src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java index 434f98641f..850054c429 100644 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java +++ b/example/src/main/java/io/netty/example/http/websocketx/client/WebSocketHttpResponseDecoder.java @@ -40,10 +40,10 @@ public class WebSocketHttpResponseDecoder extends HttpResponseDecoder { return true; } switch (code) { - case 204: - case 205: - case 304: - return true; + case 204: + case 205: + case 304: + return true; } } return false; diff --git a/src/main/java/io/netty/example/http/websocketx/client/package-info.java b/example/src/main/java/io/netty/example/http/websocketx/client/package-info.java similarity index 79% rename from src/main/java/io/netty/example/http/websocketx/client/package-info.java rename to example/src/main/java/io/netty/example/http/websocketx/client/package-info.java index b903874eaf..013ff4941b 100644 --- a/src/main/java/io/netty/example/http/websocketx/client/package-info.java +++ b/example/src/main/java/io/netty/example/http/websocketx/client/package-info.java @@ -16,9 +16,8 @@ /** *

This is an example web service client. - *

To run this example, you must first start - * io.netty.example.http.websocketx.server.WebSocketServer - *

Next, run io.netty.example.http.websocketx.client.App. + *

To run this example, you must first start {@link WebSocketServer} and + * then {@link WebSocketClient}. */ package io.netty.example.http.websocketx.client; diff --git a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java similarity index 56% rename from src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java rename to example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java index 21547883da..b2899692dd 100644 --- a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServer.java @@ -29,40 +29,49 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; * * http://localhost:8080/websocket * - * Open your browser at http://localhost:8080/, then the demo page will be - * loaded and a Web Socket connection will be made automatically. + * Open your browser at http://localhost:8080/, then the demo page will be loaded and a Web Socket connection will be + * made automatically. * - * This server illustrates support for the different web socket specification - * versions and will work with: + * This server illustrates support for the different web socket specification versions and will work with: * *

    *
  • Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) - *
  • *
  • Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) - *
  • *
  • Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) - *
  • + *
  • Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) *
  • Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) - *
  • *
*/ public class WebSocketServer { - public static void main(String[] args) { - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINE); - Logger.getLogger("").addHandler(ch); - Logger.getLogger("").setLevel(Level.FINE); - - // Configure the server. - ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( - Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); - // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); + private final int port; - // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); - - System.out.println("Web Socket Server started on 8080. Open your browser and navigate to http://localhost:8080/"); - } + public WebSocketServer(int port) { + this.port = port; + } + + public void run() { + // Configure the server. + ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); + + // Set up the event pipeline factory. + bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory()); + + // Bind and start to accept incoming connections. + bootstrap.bind(new InetSocketAddress(port)); + + System.out.println("Web socket server started at port " + port + '.'); + System.out.println("Open your browser and navigate to http://localhost:" + port + '/'); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new WebSocketServer(port).run(); + } } diff --git a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java new file mode 100644 index 0000000000..64fdcc6000 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java @@ -0,0 +1,146 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.server; + +import static io.netty.handler.codec.http.HttpHeaders.*; +import static io.netty.handler.codec.http.HttpHeaders.Names.*; +import static io.netty.handler.codec.http.HttpMethod.*; +import static io.netty.handler.codec.http.HttpResponseStatus.*; +import static io.netty.handler.codec.http.HttpVersion.*; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.CharsetUtil; + +/** + * Handles handshakes and messages + */ +public class WebSocketServerHandler extends SimpleChannelUpstreamHandler { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class); + + private static final String WEBSOCKET_PATH = "/websocket"; + + private WebSocketServerHandshaker handshaker; + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + Object msg = e.getMessage(); + if (msg instanceof HttpRequest) { + handleHttpRequest(ctx, (HttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } + } + + private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { + // Allow only GET methods. + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); + return; + } + + // Send the demo page and favicon.ico + if (req.getUri().equals("/")) { + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); + + ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); + + res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); + setContentLength(res, content.readableBytes()); + + res.setContent(content); + sendHttpResponse(ctx, req, res); + return; + } else if (req.getUri().equals("/favicon.ico")) { + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); + sendHttpResponse(ctx, req, res); + return; + } + + // Handshake + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + this.getWebSocketLocation(req), null, false); + this.handshaker = wsFactory.newHandshaker(req); + if (this.handshaker == null) { + wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); + } else { + this.handshaker.handshake(ctx.getChannel(), req); + } + } + + private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { + + // Check for closing frame + if (frame instanceof CloseWebSocketFrame) { + this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); + return; + } else if (frame instanceof PingWebSocketFrame) { + ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); + return; + } else if (!(frame instanceof TextWebSocketFrame)) { + throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() + .getName())); + } + + // Send the uppercase string back. + String request = ((TextWebSocketFrame) frame).getText(); + logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); + ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); + } + + private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { + // Generate an error page if response status code is not OK (200). + if (res.getStatus().getCode() != 200) { + res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); + setContentLength(res, res.getContent().readableBytes()); + } + + // Send the response and close the connection if necessary. + ChannelFuture f = ctx.getChannel().write(res); + if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { + f.addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + e.getCause().printStackTrace(); + e.getChannel().close(); + } + + private String getWebSocketLocation(HttpRequest req) { + return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH; + } +} diff --git a/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java new file mode 100644 index 0000000000..11ed2f518e --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java @@ -0,0 +1,96 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.server; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.util.CharsetUtil; + +/** + * Generates the demo HTML page which is served at http://localhost:8080/ + */ +public final class WebSocketServerIndexPage { + + private static final String NEWLINE = "\r\n"; + + public static ChannelBuffer getContent(String webSocketLocation) { + return ChannelBuffers + .copiedBuffer( + "Web Socket Test" + + NEWLINE + + "" + + NEWLINE + + "" + + NEWLINE + + "
" + + NEWLINE + + "" + + "" + + NEWLINE + "

Output

" + NEWLINE + + "" + + NEWLINE + "
" + NEWLINE + "" + NEWLINE + "" + NEWLINE, + CharsetUtil.US_ASCII); + } + + private WebSocketServerIndexPage() { + // Unused + } +} diff --git a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java similarity index 69% rename from src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java index 1232bda3fb..21c31d41a9 100644 --- a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerPipelineFactory.java @@ -26,14 +26,14 @@ import io.netty.handler.codec.http.HttpResponseEncoder; /** */ public class WebSocketServerPipelineFactory implements ChannelPipelineFactory { - @Override - public ChannelPipeline getPipeline() throws Exception { - // Create a default pipeline implementation. - ChannelPipeline pipeline = pipeline(); - pipeline.addLast("decoder", new HttpRequestDecoder()); - pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); - pipeline.addLast("encoder", new HttpResponseEncoder()); - pipeline.addLast("handler", new WebSocketServerHandler()); - return pipeline; - } + @Override + public ChannelPipeline getPipeline() throws Exception { + // Create a default pipeline implementation. + ChannelPipeline pipeline = pipeline(); + pipeline.addLast("decoder", new HttpRequestDecoder()); + pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); + pipeline.addLast("encoder", new HttpResponseEncoder()); + pipeline.addLast("handler", new WebSocketServerHandler()); + return pipeline; + } } diff --git a/src/main/java/io/netty/example/http/websocketx/server/package-info.java b/example/src/main/java/io/netty/example/http/websocketx/server/package-info.java similarity index 100% rename from src/main/java/io/netty/example/http/websocketx/server/package-info.java rename to example/src/main/java/io/netty/example/http/websocketx/server/package-info.java diff --git a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java new file mode 100644 index 0000000000..def9595f90 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java @@ -0,0 +1,90 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.sslserver; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.socket.nio.NioServerSocketChannelFactory; + +/** + * A HTTP server which serves Web Socket requests at: + * + * https://localhost:8081/websocket + * + * Open your browser at https://localhost:8081/, then the demo page will be loaded and a Web Socket connection will be + * made automatically. + * + * This server illustrates support for the different web socket specification versions and will work with: + * + *
    + *
  • Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) + *
  • Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) + *
  • Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) + *
  • Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) + *
  • Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) + *
+ */ +public class WebSocketSslServer { + + private final int port; + + public WebSocketSslServer(int port) { + this.port = port; + } + + public void run() { + // Configure the server. + ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); + + // Set up the event pipeline factory. + bootstrap.setPipelineFactory(new WebSocketSslServerPipelineFactory()); + + // Bind and start to accept incoming connections. + bootstrap.bind(new InetSocketAddress(port)); + + System.out.println("Web socket server started at port " + port + '.'); + System.out.println("Open your browser and navigate to https://localhost:" + port + '/'); + } + + public static void main(String[] args) { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8443; + } + + String keyStoreFilePath = System.getProperty("keystore.file.path"); + if (keyStoreFilePath == null || keyStoreFilePath.isEmpty()) { + System.out.println("ERROR: System property keystore.file.path not set. Exiting now!"); + System.exit(1); + } + + String keyStoreFilePassword = System.getProperty("keystore.file.password"); + if (keyStoreFilePassword == null || keyStoreFilePassword.isEmpty()) { + System.out.println("ERROR: System property keystore.file.password not set. Exiting now!"); + System.exit(1); + } + + new WebSocketSslServer(port).run(); + } +} diff --git a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java new file mode 100644 index 0000000000..c2a6bf6289 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java @@ -0,0 +1,146 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.sslserver; + +import static io.netty.handler.codec.http.HttpHeaders.*; +import static io.netty.handler.codec.http.HttpHeaders.Names.*; +import static io.netty.handler.codec.http.HttpMethod.*; +import static io.netty.handler.codec.http.HttpResponseStatus.*; +import static io.netty.handler.codec.http.HttpVersion.*; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.CharsetUtil; + +/** + * Handles handshakes and messages + */ +public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerHandler.class); + + private static final String WEBSOCKET_PATH = "/websocket"; + + private WebSocketServerHandshaker handshaker; + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + Object msg = e.getMessage(); + if (msg instanceof HttpRequest) { + handleHttpRequest(ctx, (HttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } + } + + private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { + // Allow only GET methods. + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); + return; + } + + // Send the demo page and favicon.ico + if (req.getUri().equals("/")) { + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); + + ChannelBuffer content = WebSocketSslServerIndexPage.getContent(getWebSocketLocation(req)); + + res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); + setContentLength(res, content.readableBytes()); + + res.setContent(content); + sendHttpResponse(ctx, req, res); + return; + } else if (req.getUri().equals("/favicon.ico")) { + HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); + sendHttpResponse(ctx, req, res); + return; + } + + // Handshake + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + this.getWebSocketLocation(req), null, false); + this.handshaker = wsFactory.newHandshaker(req); + if (this.handshaker == null) { + wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); + } else { + this.handshaker.handshake(ctx.getChannel(), req); + } + } + + private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { + + // Check for closing frame + if (frame instanceof CloseWebSocketFrame) { + this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame); + return; + } else if (frame instanceof PingWebSocketFrame) { + ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); + return; + } else if (!(frame instanceof TextWebSocketFrame)) { + throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() + .getName())); + } + + // Send the uppercase string back. + String request = ((TextWebSocketFrame) frame).getText(); + logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); + ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); + } + + private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { + // Generate an error page if response status code is not OK (200). + if (res.getStatus().getCode() != 200) { + res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); + setContentLength(res, res.getContent().readableBytes()); + } + + // Send the response and close the connection if necessary. + ChannelFuture f = ctx.getChannel().write(res); + if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { + f.addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + e.getCause().printStackTrace(); + e.getChannel().close(); + } + + private String getWebSocketLocation(HttpRequest req) { + return "wss://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH; + } +} diff --git a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java new file mode 100644 index 0000000000..ad11d8e9a5 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java @@ -0,0 +1,96 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.sslserver; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.util.CharsetUtil; + +/** + * Generates the demo HTML page which is served at http://localhost:8080/ + */ +public final class WebSocketSslServerIndexPage { + + private static final String NEWLINE = "\r\n"; + + public static ChannelBuffer getContent(String webSocketLocation) { + return ChannelBuffers + .copiedBuffer( + "Web Socket Test" + + NEWLINE + + "" + + NEWLINE + + "" + + NEWLINE + + "
" + + NEWLINE + + "" + + "" + + NEWLINE + "

Output

" + NEWLINE + + "" + + NEWLINE + "
" + NEWLINE + "" + NEWLINE + "" + NEWLINE, + CharsetUtil.US_ASCII); + } + + private WebSocketSslServerIndexPage() { + // Unused + } +} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java similarity index 74% rename from src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java rename to example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java index b80ae91c16..6393738eab 100644 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerPipelineFactory.java @@ -29,19 +29,19 @@ import io.netty.handler.ssl.SslHandler; /** */ public class WebSocketSslServerPipelineFactory implements ChannelPipelineFactory { - @Override - public ChannelPipeline getPipeline() throws Exception { - // Create a default pipeline implementation. - ChannelPipeline pipeline = pipeline(); - + @Override + public ChannelPipeline getPipeline() throws Exception { + // Create a default pipeline implementation. + ChannelPipeline pipeline = pipeline(); + SSLEngine engine = WebSocketSslServerSslContext.getInstance().getServerContext().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast("ssl", new SslHandler(engine)); - pipeline.addLast("decoder", new HttpRequestDecoder()); - pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); - pipeline.addLast("encoder", new HttpResponseEncoder()); - pipeline.addLast("handler", new WebSocketSslServerHandler()); - return pipeline; - } + pipeline.addLast("decoder", new HttpRequestDecoder()); + pipeline.addLast("aggregator", new HttpChunkAggregator(65536)); + pipeline.addLast("encoder", new HttpResponseEncoder()); + pipeline.addLast("handler", new WebSocketSslServerHandler()); + return pipeline; + } } diff --git a/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java new file mode 100644 index 0000000000..b21cd26502 --- /dev/null +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java @@ -0,0 +1,102 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.http.websocketx.sslserver; + +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.Security; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +/** + * Creates a {@link SSLContext} for just server certificates. + */ +public final class WebSocketSslServerSslContext { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerSslContext.class); + private static final String PROTOCOL = "TLS"; + private SSLContext _serverContext; + + /** + * Returns the singleton instance for this class + */ + public static WebSocketSslServerSslContext getInstance() { + return SingletonHolder.INSTANCE; + } + + /** + * SingletonHolder is loaded on the first execution of Singleton.getInstance() or the first access to + * SingletonHolder.INSTANCE, not before. + * + * See http://en.wikipedia.org/wiki/Singleton_pattern + */ + private static class SingletonHolder { + + public static final WebSocketSslServerSslContext INSTANCE = new WebSocketSslServerSslContext(); + } + + /** + * Constructor for singleton + */ + private WebSocketSslServerSslContext() { + try { + // Key store (Server side certificate) + String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); + if (algorithm == null) { + algorithm = "SunX509"; + } + + SSLContext serverContext = null; + try { + String keyStoreFilePath = System.getProperty("keystore.file.path"); + String keyStoreFilePassword = System.getProperty("keystore.file.password"); + + KeyStore ks = KeyStore.getInstance("JKS"); + FileInputStream fin = new FileInputStream(keyStoreFilePath); + ks.load(fin, keyStoreFilePassword.toCharArray()); + + // Set up key manager factory to use our key store + // Assume key password is the same as the key store file + // password + KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); + kmf.init(ks, keyStoreFilePassword.toCharArray()); + + // Initialise the SSLContext to work with our key managers. + serverContext = SSLContext.getInstance(PROTOCOL); + serverContext.init(kmf.getKeyManagers(), null, null); + } catch (Exception e) { + throw new Error("Failed to initialize the server-side SSLContext", e); + } + _serverContext = serverContext; + } catch (Exception ex) { + logger.error("Error initializing SslContextManager. " + ex.getMessage(), ex); + System.exit(1); + + } + } + + /** + * Returns the server context with server side key store + */ + public SSLContext getServerContext() { + return _serverContext; + } + +} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java b/example/src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java similarity index 62% rename from src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java rename to example/src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java index f7865b5cae..9ba84ee1b5 100644 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java +++ b/example/src/main/java/io/netty/example/http/websocketx/sslserver/package-info.java @@ -18,19 +18,16 @@ *

This package contains an example web socket web server with server SSL. *

To run this example, follow the steps below: *

- *
Step 1. Generate Your Key
- *
- * keytool -genkey -keystore mySrvKeystore -keyalg RSA. - * Make sure that you set the key password to be the same the key file password. - *
- *
Step 2. Specify your key store file and password as system properties
- *
- * -Dkeystore.file.path=<path to mySrvKeystore> -Dkeystore.file.password=<password> - *
- *
Step 3. Run WebSocketSslServer as a Java application
- *
- * Once started, you can test the web server against your browser by navigating to https://localhost:8081/ - *
+ *
Step 1. Generate Your Key + *
+ * keytool -genkey -keystore mySrvKeystore -keyalg RSA. + * Make sure that you set the key password to be the same the key file password. + *
Step 2. Specify your key store file and password as system properties + *
+ * -Dkeystore.file.path=<path to mySrvKeystore> -Dkeystore.file.password=<password> + *
Step 3. Run WebSocketSslServer as a Java application + *
+ * Once started, you can test the web server against your browser by navigating to https://localhost:8081/ *
*

To find out more about setting up key stores, refer to this * giude. diff --git a/src/main/java/io/netty/example/local/LocalExample.java b/example/src/main/java/io/netty/example/local/LocalExample.java similarity index 92% rename from src/main/java/io/netty/example/local/LocalExample.java rename to example/src/main/java/io/netty/example/local/LocalExample.java index 48358eaf55..50eaa63639 100644 --- a/src/main/java/io/netty/example/local/LocalExample.java +++ b/example/src/main/java/io/netty/example/local/LocalExample.java @@ -16,6 +16,7 @@ package io.netty.example.local; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import io.netty.bootstrap.ClientBootstrap; @@ -33,12 +34,17 @@ import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.logging.LoggingHandler; import io.netty.logging.InternalLogLevel; -/** - */ public class LocalExample { - public static void main(String[] args) throws Exception { + + private final String port; + + public LocalExample(String port) { + this.port = port; + } + + public void run() throws IOException { // Address to bind on / connect to. - LocalAddress socketAddress = new LocalAddress("1"); + LocalAddress socketAddress = new LocalAddress(port); // Configure the server. ServerBootstrap sb = new ServerBootstrap( @@ -57,7 +63,6 @@ public class LocalExample { // Set up the client-side pipeline factory. cb.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), @@ -97,4 +102,8 @@ public class LocalExample { cb.releaseExternalResources(); sb.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + new LocalExample("1").run(); + } } diff --git a/src/main/java/io/netty/example/local/LocalExampleMultthreaded.java b/example/src/main/java/io/netty/example/local/LocalExampleMultithreaded.java similarity index 90% rename from src/main/java/io/netty/example/local/LocalExampleMultthreaded.java rename to example/src/main/java/io/netty/example/local/LocalExampleMultithreaded.java index 77e5103b93..0a4e68f234 100644 --- a/src/main/java/io/netty/example/local/LocalExampleMultthreaded.java +++ b/example/src/main/java/io/netty/example/local/LocalExampleMultithreaded.java @@ -32,12 +32,16 @@ import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; import io.netty.handler.logging.LoggingHandler; import io.netty.logging.InternalLogLevel; -/** - */ -public class LocalExampleMultthreaded { +public class LocalExampleMultithreaded { - public static void main(String[] args) throws Exception { - LocalAddress socketAddress = new LocalAddress("1"); + private final String port; + + public LocalExampleMultithreaded(String port) { + this.port = port; + } + + public void run() { + LocalAddress socketAddress = new LocalAddress(port); OrderedMemoryAwareThreadPoolExecutor eventExecutor = new OrderedMemoryAwareThreadPoolExecutor( @@ -54,7 +58,6 @@ public class LocalExampleMultthreaded { new DefaultLocalClientChannelFactory()); cb.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringDecoder(), @@ -66,7 +69,7 @@ public class LocalExampleMultthreaded { // Read commands from array String[] commands = { "First", "Second", "Third", "quit" }; for (int j = 0; j < 5 ; j++) { - System.err.println("Start "+j); + System.err.println("Start " + j); ChannelFuture channelFuture = cb.connect(socketAddress); channelFuture.awaitUninterruptibly(); if (! channelFuture.isSuccess()) { @@ -87,7 +90,7 @@ public class LocalExampleMultthreaded { channelFuture.getChannel().close(); // Wait until the connection is closed or the connection attempt fails. channelFuture.getChannel().getCloseFuture().awaitUninterruptibly(); - System.err.println("End "+j); + System.err.println("End " + j); } // Release all resources @@ -95,4 +98,8 @@ public class LocalExampleMultthreaded { sb.releaseExternalResources(); eventExecutor.shutdownNow(); } + + public static void main(String[] args) throws Exception { + new LocalExampleMultithreaded("1").run(); + } } diff --git a/src/main/java/io/netty/example/local/LocalServerPipelineFactory.java b/example/src/main/java/io/netty/example/local/LocalServerPipelineFactory.java similarity index 98% rename from src/main/java/io/netty/example/local/LocalServerPipelineFactory.java rename to example/src/main/java/io/netty/example/local/LocalServerPipelineFactory.java index afa536820e..3c28c5d764 100644 --- a/src/main/java/io/netty/example/local/LocalServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/local/LocalServerPipelineFactory.java @@ -29,8 +29,6 @@ import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.execution.ExecutionHandler; -/** - */ public class LocalServerPipelineFactory implements ChannelPipelineFactory { private final ExecutionHandler executionHandler; @@ -73,7 +71,7 @@ public class LocalServerPipelineFactory implements ChannelPipelineFactory { Channels.close(e.getChannel()); return; } - System.err.println("SERVER:"+msg); + System.err.println("SERVER:" + msg); // Write back Channels.write(e.getChannel(), msg); } diff --git a/src/main/java/io/netty/example/localtime/LocalTimeClient.java b/example/src/main/java/io/netty/example/localtime/LocalTimeClient.java similarity index 90% rename from src/main/java/io/netty/example/localtime/LocalTimeClient.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeClient.java index 58ae89548c..4273fb6edb 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeClient.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeClient.java @@ -33,21 +33,18 @@ import io.netty.channel.socket.nio.NioClientSocketChannelFactory; */ public class LocalTimeClient { - public static void main(String[] args) throws Exception { - // Print usage if necessary. - if (args.length < 3) { - printUsage(); - return; - } + private final String host; + private final int port; + private final Collection cities; - // Parse options. - String host = args[0]; - int port = Integer.parseInt(args[1]); - Collection cities = parseCities(args, 2); - if (cities == null) { - return; - } + public LocalTimeClient(String host, int port, Collection cities) { + this.host = host; + this.port = port; + this.cities = new ArrayList(); + this.cities.addAll(cities); + } + public void run() { // Set up. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( @@ -84,6 +81,24 @@ public class LocalTimeClient { } } + public static void main(String[] args) throws Exception { + // Print usage if necessary. + if (args.length < 3) { + printUsage(); + return; + } + + // Parse options. + String host = args[0]; + int port = Integer.parseInt(args[1]); + Collection cities = parseCities(args, 2); + if (cities == null) { + return; + } + + new LocalTimeClient(host, port, cities).run(); + } + private static void printUsage() { System.err.println( "Usage: " + LocalTimeClient.class.getSimpleName() + diff --git a/src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java b/example/src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java similarity index 99% rename from src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java index 018b7394bb..141f750789 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeClientHandler.java @@ -37,8 +37,6 @@ import io.netty.example.localtime.LocalTimeProtocol.LocalTimes; import io.netty.example.localtime.LocalTimeProtocol.Location; import io.netty.example.localtime.LocalTimeProtocol.Locations; -/** - */ public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( diff --git a/src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java b/example/src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java similarity index 99% rename from src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java index 33d442a26a..b2b407b853 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeClientPipelineFactory.java @@ -24,8 +24,6 @@ import io.netty.handler.codec.protobuf.ProtobufEncoder; import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; -/** - */ public class LocalTimeClientPipelineFactory implements ChannelPipelineFactory { @Override diff --git a/src/main/java/io/netty/example/localtime/LocalTimeProtocol.java b/example/src/main/java/io/netty/example/localtime/LocalTimeProtocol.java similarity index 100% rename from src/main/java/io/netty/example/localtime/LocalTimeProtocol.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeProtocol.java diff --git a/src/main/java/io/netty/example/localtime/LocalTimeProtocol.proto b/example/src/main/java/io/netty/example/localtime/LocalTimeProtocol.proto similarity index 100% rename from src/main/java/io/netty/example/localtime/LocalTimeProtocol.proto rename to example/src/main/java/io/netty/example/localtime/LocalTimeProtocol.proto diff --git a/src/main/java/io/netty/example/localtime/LocalTimeServer.java b/example/src/main/java/io/netty/example/localtime/LocalTimeServer.java similarity index 80% rename from src/main/java/io/netty/example/localtime/LocalTimeServer.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeServer.java index 168d5b3a11..11aad21b06 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeServer.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeServer.java @@ -27,7 +27,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class LocalTimeServer { - public static void main(String[] args) throws Exception { + private final int port; + + public LocalTimeServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -38,6 +44,16 @@ public class LocalTimeServer { bootstrap.setPipelineFactory(new LocalTimeServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new LocalTimeServer(port).run(); } } diff --git a/src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java b/example/src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java similarity index 99% rename from src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java index 7bb8a4a246..eabb15c569 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeServerHandler.java @@ -35,8 +35,6 @@ import io.netty.example.localtime.LocalTimeProtocol.LocalTimes; import io.netty.example.localtime.LocalTimeProtocol.Location; import io.netty.example.localtime.LocalTimeProtocol.Locations; -/** - */ public class LocalTimeServerHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( diff --git a/src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java b/example/src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java similarity index 99% rename from src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java rename to example/src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java index 62bbb2dacc..8328500b3b 100644 --- a/src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java +++ b/example/src/main/java/io/netty/example/localtime/LocalTimeServerPipelineFactory.java @@ -24,8 +24,6 @@ import io.netty.handler.codec.protobuf.ProtobufEncoder; import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; -/** - */ public class LocalTimeServerPipelineFactory implements ChannelPipelineFactory { @Override diff --git a/src/main/java/io/netty/example/objectecho/ObjectEchoClient.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoClient.java similarity index 87% rename from src/main/java/io/netty/example/objectecho/ObjectEchoClient.java rename to example/src/main/java/io/netty/example/objectecho/ObjectEchoClient.java index dc36e720c7..a4ff2b5a41 100644 --- a/src/main/java/io/netty/example/objectecho/ObjectEchoClient.java +++ b/example/src/main/java/io/netty/example/objectecho/ObjectEchoClient.java @@ -32,6 +32,37 @@ import io.netty.handler.codec.serialization.ObjectEncoder; */ public class ObjectEchoClient { + private final String host; + private final int port; + private final int firstMessageSize; + + public ObjectEchoClient(String host, int port, int firstMessageSize) { + this.host = host; + this.port = port; + this.firstMessageSize = firstMessageSize; + } + + public void run() { + // Configure the client. + ClientBootstrap bootstrap = new ClientBootstrap( + new NioClientSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + + // Set up the pipeline factory. + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + public ChannelPipeline getPipeline() throws Exception { + return Channels.pipeline( + new ObjectEncoder(), + new ObjectDecoder(), + new ObjectEchoClientHandler(firstMessageSize)); + } + }); + + // Start the connection attempt. + bootstrap.connect(new InetSocketAddress(host, port)); + } + public static void main(String[] args) throws Exception { // Print usage if no argument is specified. if (args.length < 2 || args.length > 3) { @@ -52,24 +83,6 @@ public class ObjectEchoClient { firstMessageSize = 256; } - // Configure the client. - ClientBootstrap bootstrap = new ClientBootstrap( - new NioClientSocketChannelFactory( - Executors.newCachedThreadPool(), - Executors.newCachedThreadPool())); - - // Set up the pipeline factory. - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override - public ChannelPipeline getPipeline() throws Exception { - return Channels.pipeline( - new ObjectEncoder(), - new ObjectDecoder(), - new ObjectEchoClientHandler(firstMessageSize)); - } - }); - - // Start the connection attempt. - bootstrap.connect(new InetSocketAddress(host, port)); + new ObjectEchoClient(host, port, firstMessageSize).run(); } } diff --git a/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java similarity index 100% rename from src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java rename to example/src/main/java/io/netty/example/objectecho/ObjectEchoClientHandler.java diff --git a/src/main/java/io/netty/example/objectecho/ObjectEchoServer.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoServer.java similarity index 84% rename from src/main/java/io/netty/example/objectecho/ObjectEchoServer.java rename to example/src/main/java/io/netty/example/objectecho/ObjectEchoServer.java index c1915b9180..e30ebd3821 100644 --- a/src/main/java/io/netty/example/objectecho/ObjectEchoServer.java +++ b/example/src/main/java/io/netty/example/objectecho/ObjectEchoServer.java @@ -32,7 +32,13 @@ import io.netty.handler.codec.serialization.ObjectEncoder; */ public class ObjectEchoServer { - public static void main(String[] args) throws Exception { + private final int port; + + public ObjectEchoServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -41,7 +47,6 @@ public class ObjectEchoServer { // Set up the pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new ObjectEncoder(), @@ -51,6 +56,16 @@ public class ObjectEchoServer { }); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new ObjectEchoServer(port).run(); } } diff --git a/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java b/example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java similarity index 100% rename from src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java rename to example/src/main/java/io/netty/example/objectecho/ObjectEchoServerHandler.java diff --git a/src/main/java/io/netty/example/portunification/PortUnificationServer.java b/example/src/main/java/io/netty/example/portunification/PortUnificationServer.java similarity index 83% rename from src/main/java/io/netty/example/portunification/PortUnificationServer.java rename to example/src/main/java/io/netty/example/portunification/PortUnificationServer.java index 093b6c6214..1070490feb 100644 --- a/src/main/java/io/netty/example/portunification/PortUnificationServer.java +++ b/example/src/main/java/io/netty/example/portunification/PortUnificationServer.java @@ -33,7 +33,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class PortUnificationServer { - public static void main(String[] args) throws Exception { + private final int port; + + public PortUnificationServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -42,13 +48,22 @@ public class PortUnificationServer { // Set up the event pipeline factory. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new PortUnificationServerHandler()); } }); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new PortUnificationServer(port).run(); } } diff --git a/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java b/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java similarity index 97% rename from src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java rename to example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java index b18fba49e9..8c0f148113 100644 --- a/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java +++ b/example/src/main/java/io/netty/example/portunification/PortUnificationServerHandler.java @@ -24,7 +24,7 @@ import io.netty.channel.ChannelPipeline; import io.netty.example.factorial.BigIntegerDecoder; import io.netty.example.factorial.FactorialServerHandler; import io.netty.example.factorial.NumberEncoder; -import io.netty.example.http.snoop.HttpRequestHandler; +import io.netty.example.http.snoop.HttpSnoopServerHandler; import io.netty.example.securechat.SecureChatSslContextFactory; import io.netty.handler.codec.compression.ZlibDecoder; import io.netty.handler.codec.compression.ZlibEncoder; @@ -144,7 +144,7 @@ public class PortUnificationServerHandler extends FrameDecoder { p.addLast("decoder", new HttpRequestDecoder()); p.addLast("encoder", new HttpResponseEncoder()); p.addLast("deflater", new HttpContentCompressor()); - p.addLast("handler", new HttpRequestHandler()); + p.addLast("handler", new HttpSnoopServerHandler()); p.remove(this); } diff --git a/src/main/java/io/netty/example/proxy/HexDumpProxy.java b/example/src/main/java/io/netty/example/proxy/HexDumpProxy.java similarity index 85% rename from src/main/java/io/netty/example/proxy/HexDumpProxy.java rename to example/src/main/java/io/netty/example/proxy/HexDumpProxy.java index 06692b5360..44e8d5dc46 100644 --- a/src/main/java/io/netty/example/proxy/HexDumpProxy.java +++ b/example/src/main/java/io/netty/example/proxy/HexDumpProxy.java @@ -24,24 +24,19 @@ import io.netty.channel.socket.ClientSocketChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class HexDumpProxy { - public static void main(String[] args) throws Exception { - // Validate command line options. - if (args.length != 3) { - System.err.println( - "Usage: " + HexDumpProxy.class.getSimpleName() + - " "); - return; - } + private final int localPort; + private final String remoteHost; + private final int remotePort; - // Parse command line options. - int localPort = Integer.parseInt(args[0]); - String remoteHost = args[1]; - int remotePort = Integer.parseInt(args[2]); + public HexDumpProxy(int localPort, String remoteHost, int remotePort) { + this.localPort = localPort; + this.remoteHost = remoteHost; + this.remotePort = remotePort; + } + public void run() { System.err.println( "Proxying *:" + localPort + " to " + remoteHost + ':' + remotePort + " ..."); @@ -61,4 +56,21 @@ public class HexDumpProxy { // Start up the server. sb.bind(new InetSocketAddress(localPort)); } + + public static void main(String[] args) throws Exception { + // Validate command line options. + if (args.length != 3) { + System.err.println( + "Usage: " + HexDumpProxy.class.getSimpleName() + + " "); + return; + } + + // Parse command line options. + int localPort = Integer.parseInt(args[0]); + String remoteHost = args[1]; + int remotePort = Integer.parseInt(args[2]); + + new HexDumpProxy(localPort, remoteHost, remotePort).run(); + } } diff --git a/src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java b/example/src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java similarity index 99% rename from src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java rename to example/src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java index d934ca98e7..839a7d8d6a 100644 --- a/src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java +++ b/example/src/main/java/io/netty/example/proxy/HexDumpProxyInboundHandler.java @@ -30,8 +30,6 @@ import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; import io.netty.channel.socket.ClientSocketChannelFactory; -/** - */ public class HexDumpProxyInboundHandler extends SimpleChannelUpstreamHandler { private final ClientSocketChannelFactory cf; diff --git a/src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java b/example/src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java similarity index 99% rename from src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java rename to example/src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java index 935f02cd64..456110a516 100644 --- a/src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java +++ b/example/src/main/java/io/netty/example/proxy/HexDumpProxyPipelineFactory.java @@ -21,8 +21,6 @@ import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; import io.netty.channel.socket.ClientSocketChannelFactory; -/** - */ public class HexDumpProxyPipelineFactory implements ChannelPipelineFactory { private final ClientSocketChannelFactory cf; diff --git a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java similarity index 91% rename from src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java rename to example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java index 47bd87beca..986bb2b701 100644 --- a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClient.java @@ -38,7 +38,13 @@ import io.netty.util.CharsetUtil; */ public class QuoteOfTheMomentClient { - public static void main(String[] args) throws Exception { + private final int port; + + public QuoteOfTheMomentClient(int port) { + this.port = port; + } + + public void run() { DatagramChannelFactory f = new NioDatagramChannelFactory(Executors.newCachedThreadPool()); @@ -46,7 +52,6 @@ public class QuoteOfTheMomentClient { // Configure the pipeline factory. b.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringEncoder(CharsetUtil.ISO_8859_1), @@ -75,7 +80,7 @@ public class QuoteOfTheMomentClient { DatagramChannel c = (DatagramChannel) b.bind(new InetSocketAddress(0)); // Broadcast the QOTM request to port 8080. - c.write("QOTM?", new InetSocketAddress("255.255.255.255", 8080)); + c.write("QOTM?", new InetSocketAddress("255.255.255.255", port)); // QuoteOfTheMomentClientHandler will close the DatagramChannel when a // response is received. If the channel is not closed within 5 seconds, @@ -87,4 +92,14 @@ public class QuoteOfTheMomentClient { f.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new QuoteOfTheMomentClient(port).run(); + } } diff --git a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java similarity index 99% rename from src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java rename to example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java index a2f8a41036..163272616b 100644 --- a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentClientHandler.java @@ -20,8 +20,6 @@ import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -/** - */ public class QuoteOfTheMomentClientHandler extends SimpleChannelUpstreamHandler { @Override diff --git a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java similarity index 88% rename from src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java rename to example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java index 74cade2f00..fc035b8f83 100644 --- a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServer.java @@ -37,7 +37,13 @@ import io.netty.util.CharsetUtil; */ public class QuoteOfTheMomentServer { - public static void main(String[] args) throws Exception { + private final int port; + + public QuoteOfTheMomentServer(int port) { + this.port = port; + } + + public void run() { DatagramChannelFactory f = new NioDatagramChannelFactory(Executors.newCachedThreadPool()); @@ -45,7 +51,6 @@ public class QuoteOfTheMomentServer { // Configure the pipeline factory. b.setPipelineFactory(new ChannelPipelineFactory() { - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( new StringEncoder(CharsetUtil.ISO_8859_1), @@ -54,7 +59,7 @@ public class QuoteOfTheMomentServer { } }); - // Server doesn't need to enable broadcast to listen to a broadcast. + // Enable broadcast b.setOption("broadcast", "false"); // Allow packets as large as up to 1024 bytes (default is 768). @@ -72,6 +77,16 @@ public class QuoteOfTheMomentServer { new FixedReceiveBufferSizePredictorFactory(1024)); // Bind to the port and start the service. - b.bind(new InetSocketAddress(8080)); + b.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new QuoteOfTheMomentServer(port).run(); } } diff --git a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java similarity index 99% rename from src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java rename to example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java index 9bd734b5a4..6866a47de5 100644 --- a/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java +++ b/example/src/main/java/io/netty/example/qotm/QuoteOfTheMomentServerHandler.java @@ -22,8 +22,6 @@ import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -/** - */ public class QuoteOfTheMomentServerHandler extends SimpleChannelUpstreamHandler { private static final Random random = new Random(); diff --git a/src/main/java/io/netty/example/sctp/SctpClient.java b/example/src/main/java/io/netty/example/sctp/SctpClient.java similarity index 74% rename from src/main/java/io/netty/example/sctp/SctpClient.java rename to example/src/main/java/io/netty/example/sctp/SctpClient.java index d12c171fac..3357060b13 100644 --- a/src/main/java/io/netty/example/sctp/SctpClient.java +++ b/example/src/main/java/io/netty/example/sctp/SctpClient.java @@ -20,7 +20,7 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; import io.netty.channel.Channels; -import io.netty.channel.socket.sctp.SctpClientSocketChannelFactory; +import io.netty.channel.sctp.SctpClientSocketChannelFactory; import io.netty.handler.execution.ExecutionHandler; import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; @@ -32,8 +32,15 @@ import java.util.concurrent.Executors; */ public class SctpClient { - public static void main(String[] args) throws Exception { + private final String host; + private final int port; + + public SctpClient(String host, int port) { + this.host = host; + this.port = port; + } + public void run() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new SctpClientSocketChannelFactory( @@ -57,14 +64,31 @@ public class SctpClient { bootstrap.setOption("sctpNoDelay", true); // Start the connection attempt. - ChannelFuture future = bootstrap.connect(new InetSocketAddress("localhost", 2955), new InetSocketAddress("localhost", 2956)); + ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection is closed or the connection attempt fails. future.getChannel().getCloseFuture().awaitUninterruptibly(); - // Please check SctpClientHandler to see, how echo message is sent & received + // Please check SctpClientHandler to see, how echo message is sent & received // Shut down thread pools to exit. bootstrap.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + // Print usage if no argument is specified. + if (args.length != 2) { + System.err.println( + "Usage: " + SctpClient.class.getSimpleName() + + " "); + return; + } + + // Parse options. + final String host = args[0]; + final int port = Integer.parseInt(args[1]); + final int firstMessageSize; + + new SctpClient(host, port).run(); + } } diff --git a/src/main/java/io/netty/example/sctp/SctpClientHandler.java b/example/src/main/java/io/netty/example/sctp/SctpClientHandler.java similarity index 89% rename from src/main/java/io/netty/example/sctp/SctpClientHandler.java rename to example/src/main/java/io/netty/example/sctp/SctpClientHandler.java index 75702c6708..561fda3d69 100644 --- a/src/main/java/io/netty/example/sctp/SctpClientHandler.java +++ b/example/src/main/java/io/netty/example/sctp/SctpClientHandler.java @@ -15,14 +15,18 @@ */ package io.netty.example.sctp; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.*; -import io.netty.channel.socket.sctp.SctpPayload; - import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.channel.sctp.SctpPayload; + /** * Handler implementation for the echo client. It initiates the message * and upon receiving echo back to the server diff --git a/src/main/java/io/netty/example/sctp/SctpServer.java b/example/src/main/java/io/netty/example/sctp/SctpServer.java similarity index 83% rename from src/main/java/io/netty/example/sctp/SctpServer.java rename to example/src/main/java/io/netty/example/sctp/SctpServer.java index e6150556e4..a45a66e9ff 100644 --- a/src/main/java/io/netty/example/sctp/SctpServer.java +++ b/example/src/main/java/io/netty/example/sctp/SctpServer.java @@ -19,7 +19,7 @@ import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; import io.netty.channel.Channels; -import io.netty.channel.socket.sctp.SctpServerSocketChannelFactory; +import io.netty.channel.sctp.SctpServerSocketChannelFactory; import io.netty.handler.execution.ExecutionHandler; import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; @@ -30,8 +30,14 @@ import java.util.concurrent.Executors; * Echoes back any received data from a client. */ public class SctpServer { + + private final int port; + + public SctpServer(int port) { + this.port = port; + } - public static void main(String[] args) throws Exception { + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new SctpServerSocketChannelFactory( @@ -54,6 +60,16 @@ public class SctpServer { bootstrap.setOption("child.sctpNoDelay", true); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress("localhost", 2955)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 2955; + } + new SctpServer(port).run(); } } diff --git a/src/main/java/io/netty/example/sctp/SctpServerHandler.java b/example/src/main/java/io/netty/example/sctp/SctpServerHandler.java similarity index 100% rename from src/main/java/io/netty/example/sctp/SctpServerHandler.java rename to example/src/main/java/io/netty/example/sctp/SctpServerHandler.java diff --git a/src/main/java/io/netty/example/securechat/SecureChatClient.java b/example/src/main/java/io/netty/example/securechat/SecureChatClient.java similarity index 92% rename from src/main/java/io/netty/example/securechat/SecureChatClient.java rename to example/src/main/java/io/netty/example/securechat/SecureChatClient.java index 3d137f9d5d..334c846855 100644 --- a/src/main/java/io/netty/example/securechat/SecureChatClient.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatClient.java @@ -16,6 +16,7 @@ package io.netty.example.securechat; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.util.concurrent.Executors; @@ -31,19 +32,15 @@ import io.netty.example.telnet.TelnetClient; */ public class SecureChatClient { - public static void main(String[] args) throws Exception { - // Print usage if no argument is specified. - if (args.length != 2) { - System.err.println( - "Usage: " + SecureChatClient.class.getSimpleName() + - " "); - return; - } + private final String host; + private final int port; - // Parse options. - String host = args[0]; - int port = Integer.parseInt(args[1]); + public SecureChatClient(String host, int port) { + this.host = host; + this.port = port; + } + public void run() throws IOException { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( @@ -96,4 +93,20 @@ public class SecureChatClient { // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + // Print usage if no argument is specified. + if (args.length != 2) { + System.err.println( + "Usage: " + SecureChatClient.class.getSimpleName() + + " "); + return; + } + + // Parse options. + String host = args[0]; + int port = Integer.parseInt(args[1]); + + new SecureChatClient(host, port).run(); + } } diff --git a/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java b/example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java similarity index 100% rename from src/main/java/io/netty/example/securechat/SecureChatClientHandler.java rename to example/src/main/java/io/netty/example/securechat/SecureChatClientHandler.java diff --git a/src/main/java/io/netty/example/securechat/SecureChatClientPipelineFactory.java b/example/src/main/java/io/netty/example/securechat/SecureChatClientPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/securechat/SecureChatClientPipelineFactory.java rename to example/src/main/java/io/netty/example/securechat/SecureChatClientPipelineFactory.java diff --git a/src/main/java/io/netty/example/securechat/SecureChatKeyStore.java b/example/src/main/java/io/netty/example/securechat/SecureChatKeyStore.java similarity index 99% rename from src/main/java/io/netty/example/securechat/SecureChatKeyStore.java rename to example/src/main/java/io/netty/example/securechat/SecureChatKeyStore.java index 8d5b96a361..e859bdbb7e 100644 --- a/src/main/java/io/netty/example/securechat/SecureChatKeyStore.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatKeyStore.java @@ -30,7 +30,7 @@ import java.io.InputStream; * -keystore cert.jks *

*/ -public class SecureChatKeyStore { +public final class SecureChatKeyStore { private static final short[] DATA = { 0xfe, 0xed, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, diff --git a/src/main/java/io/netty/example/securechat/SecureChatServer.java b/example/src/main/java/io/netty/example/securechat/SecureChatServer.java similarity index 80% rename from src/main/java/io/netty/example/securechat/SecureChatServer.java rename to example/src/main/java/io/netty/example/securechat/SecureChatServer.java index cce842afd7..f93274e3ea 100644 --- a/src/main/java/io/netty/example/securechat/SecureChatServer.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatServer.java @@ -27,7 +27,13 @@ import io.netty.example.telnet.TelnetServer; */ public class SecureChatServer { - public static void main(String[] args) throws Exception { + private final int port; + + public SecureChatServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -38,6 +44,16 @@ public class SecureChatServer { bootstrap.setPipelineFactory(new SecureChatServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8443; + } + new SecureChatServer(port).run(); } } diff --git a/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java b/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java similarity index 99% rename from src/main/java/io/netty/example/securechat/SecureChatServerHandler.java rename to example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java index a99b7db617..98bed94908 100644 --- a/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatServerHandler.java @@ -105,8 +105,6 @@ public class SecureChatServerHandler extends SimpleChannelUpstreamHandler { e.getChannel().close(); } - /** - */ private static final class Greeter implements ChannelFutureListener { private final SslHandler sslHandler; diff --git a/src/main/java/io/netty/example/securechat/SecureChatServerPipelineFactory.java b/example/src/main/java/io/netty/example/securechat/SecureChatServerPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/securechat/SecureChatServerPipelineFactory.java rename to example/src/main/java/io/netty/example/securechat/SecureChatServerPipelineFactory.java diff --git a/src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java b/example/src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java similarity index 97% rename from src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java rename to example/src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java index edd3c61758..c46de1c73c 100644 --- a/src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java +++ b/example/src/main/java/io/netty/example/securechat/SecureChatSslContextFactory.java @@ -49,7 +49,7 @@ import io.netty.handler.ssl.SslHandler; * to validate the client certificate. * */ -public class SecureChatSslContextFactory { +public final class SecureChatSslContextFactory { private static final String PROTOCOL = "TLS"; private static final SSLContext SERVER_CONTEXT; @@ -99,4 +99,8 @@ public class SecureChatSslContextFactory { public static SSLContext getClientContext() { return CLIENT_CONTEXT; } + + private SecureChatSslContextFactory() { + // Unused + } } diff --git a/src/main/java/io/netty/example/securechat/SecureChatTrustManagerFactory.java b/example/src/main/java/io/netty/example/securechat/SecureChatTrustManagerFactory.java similarity index 100% rename from src/main/java/io/netty/example/securechat/SecureChatTrustManagerFactory.java rename to example/src/main/java/io/netty/example/securechat/SecureChatTrustManagerFactory.java diff --git a/example/src/main/java/io/netty/example/stdio/StdioLogger.java b/example/src/main/java/io/netty/example/stdio/StdioLogger.java new file mode 100755 index 0000000000..684f4799e5 --- /dev/null +++ b/example/src/main/java/io/netty/example/stdio/StdioLogger.java @@ -0,0 +1,100 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.example.stdio; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.netty.bootstrap.ClientBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPipelineFactory; +import io.netty.channel.DefaultChannelPipeline; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelHandler; +import io.netty.channel.iostream.IoStreamAddress; +import io.netty.channel.iostream.IoStreamChannelFactory; +import io.netty.handler.codec.frame.DelimiterBasedFrameDecoder; +import io.netty.handler.codec.frame.Delimiters; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; + +/** + * An example demonstrating the use of the {@link io.netty.channel.iostream.IoStreamChannel}. + */ +public class StdioLogger { + + private volatile boolean running = true; + + public void run() { + final ExecutorService executorService = Executors.newCachedThreadPool(); + final ClientBootstrap bootstrap = new ClientBootstrap(new IoStreamChannelFactory(executorService)); + + // Configure the event pipeline factory. + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() throws Exception { + DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); + pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); + pipeline.addLast("decoder", new StringDecoder()); + pipeline.addLast("encoder", new StringEncoder()); + pipeline.addLast("loggingHandler", new SimpleChannelHandler() { + @Override + public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) + throws Exception { + + final String message = (String) e.getMessage(); + synchronized (System.out) { + e.getChannel().write("Message received: " + message); + } + if ("exit".equals(message)) { + running = false; + } + super.messageReceived(ctx, e); + } + } + ); + return pipeline; + } + }); + + // Make a new connection. + ChannelFuture connectFuture = bootstrap.connect(new IoStreamAddress(System.in, System.out)); + + // Wait until the connection is made successfully. + Channel channel = connectFuture.awaitUninterruptibly().getChannel(); + + while (running) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + // Close the connection. + channel.close().awaitUninterruptibly(); + + // Shut down all thread pools to exit. + bootstrap.releaseExternalResources(); + } + + public static void main(String[] args) { + new StdioLogger().run(); + } +} diff --git a/src/main/java/io/netty/example/telnet/TelnetClient.java b/example/src/main/java/io/netty/example/telnet/TelnetClient.java similarity index 92% rename from src/main/java/io/netty/example/telnet/TelnetClient.java rename to example/src/main/java/io/netty/example/telnet/TelnetClient.java index 97dd175b55..28c676b7ef 100644 --- a/src/main/java/io/netty/example/telnet/TelnetClient.java +++ b/example/src/main/java/io/netty/example/telnet/TelnetClient.java @@ -16,6 +16,7 @@ package io.netty.example.telnet; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.util.concurrent.Executors; @@ -30,19 +31,15 @@ import io.netty.channel.socket.nio.NioClientSocketChannelFactory; */ public class TelnetClient { - public static void main(String[] args) throws Exception { - // Print usage if no argument is specified. - if (args.length != 2) { - System.err.println( - "Usage: " + TelnetClient.class.getSimpleName() + - " "); - return; - } + private final String host; + private final int port; - // Parse options. - String host = args[0]; - int port = Integer.parseInt(args[1]); + public TelnetClient(String host, int port) { + this.host = host; + this.port = port; + } + public void run() throws IOException { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( @@ -95,4 +92,20 @@ public class TelnetClient { // Shut down all thread pools to exit. bootstrap.releaseExternalResources(); } + + public static void main(String[] args) throws Exception { + // Print usage if no argument is specified. + if (args.length != 2) { + System.err.println( + "Usage: " + TelnetClient.class.getSimpleName() + + " "); + return; + } + + // Parse options. + String host = args[0]; + int port = Integer.parseInt(args[1]); + + new TelnetClient(host, port).run(); + } } diff --git a/src/main/java/io/netty/example/telnet/TelnetClientHandler.java b/example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java similarity index 100% rename from src/main/java/io/netty/example/telnet/TelnetClientHandler.java rename to example/src/main/java/io/netty/example/telnet/TelnetClientHandler.java diff --git a/src/main/java/io/netty/example/telnet/TelnetClientPipelineFactory.java b/example/src/main/java/io/netty/example/telnet/TelnetClientPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/telnet/TelnetClientPipelineFactory.java rename to example/src/main/java/io/netty/example/telnet/TelnetClientPipelineFactory.java diff --git a/src/main/java/io/netty/example/telnet/TelnetServer.java b/example/src/main/java/io/netty/example/telnet/TelnetServer.java similarity index 79% rename from src/main/java/io/netty/example/telnet/TelnetServer.java rename to example/src/main/java/io/netty/example/telnet/TelnetServer.java index 633b88df5e..4e2aa23e16 100644 --- a/src/main/java/io/netty/example/telnet/TelnetServer.java +++ b/example/src/main/java/io/netty/example/telnet/TelnetServer.java @@ -26,7 +26,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannelFactory; */ public class TelnetServer { - public static void main(String[] args) throws Exception { + private final int port; + + public TelnetServer(int port) { + this.port = port; + } + + public void run() { // Configure the server. ServerBootstrap bootstrap = new ServerBootstrap( new NioServerSocketChannelFactory( @@ -37,6 +43,16 @@ public class TelnetServer { bootstrap.setPipelineFactory(new TelnetServerPipelineFactory()); // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8080)); + bootstrap.bind(new InetSocketAddress(port)); + } + + public static void main(String[] args) throws Exception { + int port; + if (args.length > 0) { + port = Integer.parseInt(args[0]); + } else { + port = 8080; + } + new TelnetServer(port).run(); } } diff --git a/src/main/java/io/netty/example/telnet/TelnetServerHandler.java b/example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java similarity index 100% rename from src/main/java/io/netty/example/telnet/TelnetServerHandler.java rename to example/src/main/java/io/netty/example/telnet/TelnetServerHandler.java diff --git a/src/main/java/io/netty/example/telnet/TelnetServerPipelineFactory.java b/example/src/main/java/io/netty/example/telnet/TelnetServerPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/example/telnet/TelnetServerPipelineFactory.java rename to example/src/main/java/io/netty/example/telnet/TelnetServerPipelineFactory.java diff --git a/src/main/java/io/netty/example/uptime/UptimeClient.java b/example/src/main/java/io/netty/example/uptime/UptimeClient.java similarity index 92% rename from src/main/java/io/netty/example/uptime/UptimeClient.java rename to example/src/main/java/io/netty/example/uptime/UptimeClient.java index d63b981278..1984a61c91 100644 --- a/src/main/java/io/netty/example/uptime/UptimeClient.java +++ b/example/src/main/java/io/netty/example/uptime/UptimeClient.java @@ -42,19 +42,15 @@ public class UptimeClient { // Reconnect when the server sends nothing for 10 seconds. private static final int READ_TIMEOUT = 10; - public static void main(String[] args) throws Exception { - // Print usage if no argument is specified. - if (args.length != 2) { - System.err.println( - "Usage: " + UptimeClient.class.getSimpleName() + - " "); - return; - } + private final String host; + private final int port; - // Parse options. - String host = args[0]; - int port = Integer.parseInt(args[1]); + public UptimeClient(String host, int port) { + this.host = host; + this.port = port; + } + public void run() { // Initialize the timer that schedules subsequent reconnection attempts. final Timer timer = new HashedWheelTimer(); @@ -72,7 +68,6 @@ public class UptimeClient { private final ChannelHandler uptimeHandler = new UptimeClientHandler(bootstrap, timer); - @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline( timeoutHandler, uptimeHandler); @@ -86,4 +81,20 @@ public class UptimeClient { // UptimeClientHandler. bootstrap.connect(); } + + public static void main(String[] args) throws Exception { + // Print usage if no argument is specified. + if (args.length != 2) { + System.err.println( + "Usage: " + UptimeClient.class.getSimpleName() + + " "); + return; + } + + // Parse options. + String host = args[0]; + int port = Integer.parseInt(args[1]); + + new UptimeClient(host, port).run(); + } } diff --git a/src/main/java/io/netty/example/uptime/UptimeClientHandler.java b/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java similarity index 98% rename from src/main/java/io/netty/example/uptime/UptimeClientHandler.java rename to example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java index f3fce5f542..096e575db6 100644 --- a/src/main/java/io/netty/example/uptime/UptimeClientHandler.java +++ b/example/src/main/java/io/netty/example/uptime/UptimeClientHandler.java @@ -57,7 +57,6 @@ public class UptimeClientHandler extends SimpleChannelUpstreamHandler { public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) { println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + "s"); timer.newTimeout(new TimerTask() { - @Override public void run(Timeout timeout) throws Exception { println("Reconnecting to: " + getRemoteAddress()); bootstrap.connect(); @@ -84,8 +83,7 @@ public class UptimeClientHandler extends SimpleChannelUpstreamHandler { if (cause instanceof ReadTimeoutException) { // The connection was OK but there was no traffic for last period. println("Disconnecting due to no inbound traffic"); - } - else { + } else { cause.printStackTrace(); } ctx.getChannel().close(); diff --git a/handler/pom.xml b/handler/pom.xml new file mode 100644 index 0000000000..9c9c64263e --- /dev/null +++ b/handler/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-handler + jar + + Netty/Handler + + + + ${project.groupId} + netty-buffer + ${project.version} + + + ${project.groupId} + netty-codec + ${project.version} + + + ${project.groupId} + netty-transport + ${project.version} + + + + + + + + + diff --git a/handler/src/main/java/io/netty/handler/execution/ChainedExecutor.java b/handler/src/main/java/io/netty/handler/execution/ChainedExecutor.java new file mode 100644 index 0000000000..cd8ecca099 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/execution/ChainedExecutor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + + +import java.util.concurrent.Executor; + +import io.netty.util.ExternalResourceReleasable; +import io.netty.util.internal.ExecutorUtil; + +/** + * A special {@link Executor} which allows to chain a series of + * {@link Executor}s and {@link ChannelEventRunnableFilter}. + */ +public class ChainedExecutor implements Executor, ExternalResourceReleasable { + + private final Executor cur; + private final Executor next; + private final ChannelEventRunnableFilter filter; + + /** + * Create a new {@link ChainedExecutor} which will used the given {@link ChannelEventRunnableFilter} to see if the {@link #cur} {@link Executor} should get used. + * Otherwise it will pass the work to the {@link #next} {@link Executor} + * + * @param filter the {@link ChannelEventRunnableFilter} which will be used to check if the {@link ChannelEventRunnable} should be passed to the cur or next {@link Executor} + * @param cur the {@link Executor} to use if the {@link ChannelEventRunnableFilter} match + * @param next the {@link Executor} to use if the {@link ChannelEventRunnableFilter} does not match + */ + public ChainedExecutor(ChannelEventRunnableFilter filter, Executor cur, Executor next) { + if (filter == null) { + throw new NullPointerException("filter"); + } + if (cur == null) { + throw new NullPointerException("cur"); + } + if (next == null) { + throw new NullPointerException("next"); + } + + this.filter = filter; + this.cur = cur; + this.next = next; + } + + /** + * Execute the passed {@link ChannelEventRunnable} with the current {@link Executor} if the {@link ChannelEventRunnableFilter} match. + * Otherwise pass it to the next {@link Executor} in the chain. + */ + @Override + public void execute(Runnable command) { + assert command instanceof ChannelEventRunnable; + if (filter.filter((ChannelEventRunnable) command)) { + cur.execute(command); + } else { + next.execute(command); + } + } + + @Override + public void releaseExternalResources() { + ExecutorUtil.terminate(cur, next); + releaseExternal(cur); + releaseExternal(next); + } + + + private static void releaseExternal(Executor executor) { + if (executor instanceof ExternalResourceReleasable) { + ((ExternalResourceReleasable) executor).releaseExternalResources(); + } + } +} diff --git a/src/main/java/io/netty/handler/execution/seda/ChannelDownstreamEventRunnable.java b/handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnable.java similarity index 84% rename from src/main/java/io/netty/handler/execution/seda/ChannelDownstreamEventRunnable.java rename to handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnable.java index 95c8360c76..886d6f9f9e 100644 --- a/src/main/java/io/netty/handler/execution/seda/ChannelDownstreamEventRunnable.java +++ b/handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnable.java @@ -13,17 +13,16 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.execution.seda; +package io.netty.handler.execution; import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.execution.ChannelEventRunnable; /** - * A {@link Runnable} which sends the specified {@link ChannelEvent} downstream. + * A {@link ChannelEventRunnable} which sends the specified {@link ChannelEvent} downstream. */ -public class ChannelDownstreamEventRunnable extends ChannelEventRunnable{ +public class ChannelDownstreamEventRunnable extends ChannelEventRunnable { public ChannelDownstreamEventRunnable(ChannelHandlerContext ctx, ChannelEvent e) { super(ctx, e); @@ -36,5 +35,4 @@ public class ChannelDownstreamEventRunnable extends ChannelEventRunnable{ public void run() { ctx.sendDownstream(e); } - } diff --git a/src/main/java/io/netty/container/microcontainer/NettyLoggerConfigurator.java b/handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnableFilter.java similarity index 62% rename from src/main/java/io/netty/container/microcontainer/NettyLoggerConfigurator.java rename to handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnableFilter.java index e06f91c7b8..8139622bec 100644 --- a/src/main/java/io/netty/container/microcontainer/NettyLoggerConfigurator.java +++ b/handler/src/main/java/io/netty/handler/execution/ChannelDownstreamEventRunnableFilter.java @@ -1,28 +1,28 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.container.microcontainer; - -import io.netty.logging.InternalLoggerFactory; -import io.netty.logging.JBossLoggerFactory; - -/** - * A bean that configures the default {@link InternalLoggerFactory}. - */ -public class NettyLoggerConfigurator { - public NettyLoggerConfigurator() { - InternalLoggerFactory.setDefaultFactory(new JBossLoggerFactory()); - } -} +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +/** + * {@link ChannelEventRunnableFilter} implementation which matches {@link ChannelDownstreamEventRunnable} + * + */ +public class ChannelDownstreamEventRunnableFilter implements ChannelEventRunnableFilter { + + @Override + public boolean filter(ChannelEventRunnable event) { + return event instanceof ChannelDownstreamEventRunnable; + } +} diff --git a/src/main/java/io/netty/handler/execution/ChannelEventRunnable.java b/handler/src/main/java/io/netty/handler/execution/ChannelEventRunnable.java similarity index 78% rename from src/main/java/io/netty/handler/execution/ChannelEventRunnable.java rename to handler/src/main/java/io/netty/handler/execution/ChannelEventRunnable.java index af24fb7105..b119e7a66a 100644 --- a/src/main/java/io/netty/handler/execution/ChannelEventRunnable.java +++ b/handler/src/main/java/io/netty/handler/execution/ChannelEventRunnable.java @@ -1,71 +1,56 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.execution; - -import java.util.concurrent.Executor; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelHandlerContext; -import io.netty.util.EstimatableObjectWrapper; - -/** - * a {@link Runnable} which sends the specified {@link ChannelEvent} upstream. - * Most users will not see this type at all because it is used by - * {@link Executor} implementers only - */ -public class ChannelEventRunnable implements Runnable, EstimatableObjectWrapper { - - protected final ChannelHandlerContext ctx; - protected final ChannelEvent e; - int estimatedSize; - - /** - * Creates a {@link Runnable} which sends the specified {@link ChannelEvent} - * upstream via the specified {@link ChannelHandlerContext}. - */ - public ChannelEventRunnable(ChannelHandlerContext ctx, ChannelEvent e) { - this.ctx = ctx; - this.e = e; - } - - /** - * Returns the {@link ChannelHandlerContext} which will be used to - * send the {@link ChannelEvent} upstream. - */ - public ChannelHandlerContext getContext() { - return ctx; - } - - /** - * Returns the {@link ChannelEvent} which will be sent upstream. - */ - public ChannelEvent getEvent() { - return e; - } - - /** - * Sends the event upstream. - */ - @Override - public void run() { - ctx.sendUpstream(e); - } - - @Override - public Object unwrap() { - return e; - } -} +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.EstimatableObjectWrapper; + +public abstract class ChannelEventRunnable implements Runnable, EstimatableObjectWrapper { + + protected final ChannelHandlerContext ctx; + protected final ChannelEvent e; + int estimatedSize; + + /** + * Creates a {@link Runnable} which sends the specified {@link ChannelEvent} + * upstream via the specified {@link ChannelHandlerContext}. + */ + public ChannelEventRunnable(ChannelHandlerContext ctx, ChannelEvent e) { + this.ctx = ctx; + this.e = e; + } + + /** + * Returns the {@link ChannelHandlerContext} which will be used to + * send the {@link ChannelEvent} upstream. + */ + public ChannelHandlerContext getContext() { + return ctx; + } + + /** + * Returns the {@link ChannelEvent} which will be sent upstream. + */ + public ChannelEvent getEvent() { + return e; + } + + @Override + public Object unwrap() { + return e; + } +} diff --git a/handler/src/main/java/io/netty/handler/execution/ChannelEventRunnableFilter.java b/handler/src/main/java/io/netty/handler/execution/ChannelEventRunnableFilter.java new file mode 100644 index 0000000000..1f2d6a83ce --- /dev/null +++ b/handler/src/main/java/io/netty/handler/execution/ChannelEventRunnableFilter.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +import java.util.concurrent.Executor; + +public interface ChannelEventRunnableFilter { + + /** + * Return true if the {@link ChannelEventRunnable} should get handled by the {@link Executor} + * + */ + boolean filter(ChannelEventRunnable event); +} diff --git a/handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnable.java b/handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnable.java new file mode 100644 index 0000000000..0aa67bea14 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnable.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +import java.util.concurrent.Executor; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelHandlerContext; + +/** + * A {@link ChannelEventRunnable} which sends the specified {@link ChannelEvent} upstream. + * Most users will not see this type at all because it is used by + * {@link Executor} implementers only + */ +public class ChannelUpstreamEventRunnable extends ChannelEventRunnable { + + + /** + * Creates a {@link Runnable} which sends the specified {@link ChannelEvent} + * upstream via the specified {@link ChannelHandlerContext}. + */ + public ChannelUpstreamEventRunnable(ChannelHandlerContext ctx, ChannelEvent e) { + super(ctx, e); + } + + + /** + * Sends the event upstream. + */ + @Override + public void run() { + ctx.sendUpstream(e); + } +} diff --git a/src/main/java/io/netty/container/spring/NettyLoggerConfigurator.java b/handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnableFilter.java similarity index 63% rename from src/main/java/io/netty/container/spring/NettyLoggerConfigurator.java rename to handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnableFilter.java index 295048a76e..9349cd7b26 100644 --- a/src/main/java/io/netty/container/spring/NettyLoggerConfigurator.java +++ b/handler/src/main/java/io/netty/handler/execution/ChannelUpstreamEventRunnableFilter.java @@ -1,28 +1,26 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.container.spring; - -import io.netty.logging.CommonsLoggerFactory; -import io.netty.logging.InternalLoggerFactory; - -/** - * A bean that configures the default {@link InternalLoggerFactory}. - */ -public class NettyLoggerConfigurator { - public NettyLoggerConfigurator() { - InternalLoggerFactory.setDefaultFactory(new CommonsLoggerFactory()); - } -} +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +/** + * {@link ChannelEventRunnableFilter} which matches {@link ChannelDownstreamEventRunnable} + */ +public class ChannelUpstreamEventRunnableFilter implements ChannelEventRunnableFilter { + @Override + public boolean filter(ChannelEventRunnable event) { + return event instanceof ChannelDownstreamEventRunnable; + } +} diff --git a/src/main/java/io/netty/util/DefaultObjectSizeEstimator.java b/handler/src/main/java/io/netty/handler/execution/DefaultObjectSizeEstimator.java similarity index 99% rename from src/main/java/io/netty/util/DefaultObjectSizeEstimator.java rename to handler/src/main/java/io/netty/handler/execution/DefaultObjectSizeEstimator.java index 806986a062..738ca828d1 100644 --- a/src/main/java/io/netty/util/DefaultObjectSizeEstimator.java +++ b/handler/src/main/java/io/netty/handler/execution/DefaultObjectSizeEstimator.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.util; +package io.netty.handler.execution; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/handler/src/main/java/io/netty/handler/execution/EstimatableObjectWrapper.java b/handler/src/main/java/io/netty/handler/execution/EstimatableObjectWrapper.java new file mode 100644 index 0000000000..21e55a97f0 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/execution/EstimatableObjectWrapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.execution; + +/** + * Represents an object which contains another object that needs to be taken + * into account by {@link ObjectSizeEstimator} for more accurate object size + * estimation. + */ +public interface EstimatableObjectWrapper { + + /** + * Returns the underlying object that needs to be taken into account + * by {@link ObjectSizeEstimator} for more accurate object size estimation. + */ + Object unwrap(); +} diff --git a/src/main/java/io/netty/handler/execution/ExecutionHandler.java b/handler/src/main/java/io/netty/handler/execution/ExecutionHandler.java similarity index 84% rename from src/main/java/io/netty/handler/execution/ExecutionHandler.java rename to handler/src/main/java/io/netty/handler/execution/ExecutionHandler.java index 6583a00300..de2f435666 100644 --- a/src/main/java/io/netty/handler/execution/ExecutionHandler.java +++ b/handler/src/main/java/io/netty/handler/execution/ExecutionHandler.java @@ -22,6 +22,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelDownstreamHandler; import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; @@ -29,8 +30,6 @@ import io.netty.channel.ChannelState; import io.netty.channel.ChannelStateEvent; import io.netty.channel.ChannelUpstreamHandler; import io.netty.channel.Channels; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.handler.execution.seda.SedaExecutor; import io.netty.util.ExternalResourceReleasable; import io.netty.util.internal.ExecutorUtil; @@ -94,7 +93,6 @@ import io.netty.util.internal.ExecutorUtil; * You can implement an alternative thread model such as * SEDA * by adding more than one {@link ExecutionHandler} to the pipeline. - * Alternative you may want to have a look at {@link SedaExecutor}. * *

Using other {@link Executor} implementation

* @@ -103,6 +101,7 @@ import io.netty.util.internal.ExecutorUtil; * that other {@link Executor} implementation might break your application * because they often do not maintain event execution order nor interact with * I/O threads to control the incoming traffic and avoid {@link OutOfMemoryError}. + * * @apiviz.landmark * @apiviz.has java.util.concurrent.ThreadPoolExecutor */ @@ -110,16 +109,26 @@ import io.netty.util.internal.ExecutorUtil; public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler, ExternalResourceReleasable { private final Executor executor; + private final boolean handleDownstream; /** * Creates a new instance with the specified {@link Executor}. * Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure. */ public ExecutionHandler(Executor executor) { + this(executor, false); + } + + /** + * Creates a new instance with the specified {@link Executor}. + * Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure. + */ + public ExecutionHandler(Executor executor, boolean handleDownstream) { if (executor == null) { throw new NullPointerException("executor"); } this.executor = executor; + this.handleDownstream = handleDownstream; } /** @@ -135,29 +144,36 @@ public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstre */ @Override public void releaseExternalResources() { - ExecutorUtil.terminate(getExecutor()); + Executor executor = getExecutor(); + ExecutorUtil.terminate(executor); + if (executor instanceof ExternalResourceReleasable) { + ((ExternalResourceReleasable) executor).releaseExternalResources(); + } } @Override public void handleUpstream( ChannelHandlerContext context, ChannelEvent e) throws Exception { - executor.execute(new ChannelEventRunnable(context, e)); + executor.execute(new ChannelUpstreamEventRunnable(context, e)); } @Override public void handleDownstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { - handleReadSuspend(ctx, e); - ctx.sendDownstream(e); + // check if the read was suspend + if (!handleReadSuspend(ctx, e)) { + if (handleDownstream) { + executor.execute(new ChannelDownstreamEventRunnable(ctx, e)); + } else { + ctx.sendDownstream(e); + } + } } /** * Handle suspended reads - * - * @param ctx - * @param e */ - protected void handleReadSuspend(ChannelHandlerContext ctx, ChannelEvent e) { + protected boolean handleReadSuspend(ChannelHandlerContext ctx, ChannelEvent e) { if (e instanceof ChannelStateEvent) { ChannelStateEvent cse = (ChannelStateEvent) e; if (cse.getState() == ChannelState.INTEREST_OPS && @@ -169,9 +185,11 @@ public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstre // Drop the request silently if MemoryAwareThreadPool has // set the flag. e.getFuture().setSuccess(); - return; + return true; } } } + + return false; } } diff --git a/src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java b/handler/src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java similarity index 98% rename from src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java rename to handler/src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java index 276ab1f5fe..7d6589b10d 100644 --- a/src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java +++ b/handler/src/main/java/io/netty/handler/execution/MemoryAwareThreadPoolExecutor.java @@ -33,8 +33,6 @@ import io.netty.channel.ChannelState; import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.channel.WriteCompletionEvent; -import io.netty.util.DefaultObjectSizeEstimator; -import io.netty.util.ObjectSizeEstimator; import io.netty.util.internal.ConcurrentIdentityHashMap; import io.netty.util.internal.QueueFactory; import io.netty.util.internal.SharedResourceMisuseDetector; @@ -315,6 +313,9 @@ public class MemoryAwareThreadPoolExecutor extends ThreadPoolExecutor { @Override public void execute(Runnable command) { + if (command instanceof ChannelDownstreamEventRunnable) { + throw new RejectedExecutionException("command must be enclosed with an upstream event."); + } if (!(command instanceof ChannelEventRunnable)) { command = new MemoryAwareRunnable(command); } @@ -451,8 +452,8 @@ public class MemoryAwareThreadPoolExecutor extends ThreadPoolExecutor { * make sure important tasks are not counted. */ protected boolean shouldCount(Runnable task) { - if (task instanceof ChannelEventRunnable) { - ChannelEventRunnable r = (ChannelEventRunnable) task; + if (task instanceof ChannelUpstreamEventRunnable) { + ChannelUpstreamEventRunnable r = (ChannelUpstreamEventRunnable) task; ChannelEvent e = r.getEvent(); if (e instanceof WriteCompletionEvent) { return false; @@ -477,9 +478,6 @@ public class MemoryAwareThreadPoolExecutor extends ThreadPoolExecutor { } private static final class NewThreadRunsPolicy implements RejectedExecutionHandler { - NewThreadRunsPolicy() { - } - @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { diff --git a/src/main/java/io/netty/util/ObjectSizeEstimator.java b/handler/src/main/java/io/netty/handler/execution/ObjectSizeEstimator.java similarity index 96% rename from src/main/java/io/netty/util/ObjectSizeEstimator.java rename to handler/src/main/java/io/netty/handler/execution/ObjectSizeEstimator.java index 8810282d14..5603687f92 100644 --- a/src/main/java/io/netty/util/ObjectSizeEstimator.java +++ b/handler/src/main/java/io/netty/handler/execution/ObjectSizeEstimator.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.util; +package io.netty.handler.execution; /** diff --git a/src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java b/handler/src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java similarity index 98% rename from src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java rename to handler/src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java index 924c329a45..06699125d2 100644 --- a/src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java +++ b/handler/src/main/java/io/netty/handler/execution/OrderedMemoryAwareThreadPoolExecutor.java @@ -29,7 +29,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelState; import io.netty.channel.ChannelStateEvent; -import io.netty.util.ObjectSizeEstimator; import io.netty.util.internal.ConcurrentIdentityWeakKeyHashMap; import io.netty.util.internal.QueueFactory; @@ -128,6 +127,7 @@ import io.netty.util.internal.QueueFactory; * use a weak key map such as ConcurrentWeakHashMap * or synchronized {@link WeakHashMap} instead of managing the life cycle of the * keys by yourself. + * * @apiviz.landmark */ public class OrderedMemoryAwareThreadPoolExecutor extends @@ -259,7 +259,7 @@ public class OrderedMemoryAwareThreadPoolExecutor extends ChannelStateEvent se = (ChannelStateEvent) e; if (se.getState() == ChannelState.OPEN && !channel.isOpen()) { - childExecutors.remove(channel); + removeChildExecutor(key); } } return executor; @@ -280,18 +280,15 @@ public class OrderedMemoryAwareThreadPoolExecutor extends private final class ChildExecutor implements Executor, Runnable { private final Queue tasks = QueueFactory.createQueue(Runnable.class); - private final AtomicBoolean isRunning = new AtomicBoolean(false); + private final AtomicBoolean isRunning = new AtomicBoolean(); - ChildExecutor() { - } - @Override public void execute(Runnable command) { // TODO: What todo if the add return false ? tasks.add(command); - if (isRunning.get() == false) { + if (!isRunning.get()) { doUnorderedExecute(this); } } diff --git a/src/main/java/io/netty/handler/execution/package-info.java b/handler/src/main/java/io/netty/handler/execution/package-info.java similarity index 93% rename from src/main/java/io/netty/handler/execution/package-info.java rename to handler/src/main/java/io/netty/handler/execution/package-info.java index b2e03b906e..910f4a53dc 100644 --- a/src/main/java/io/netty/handler/execution/package-info.java +++ b/handler/src/main/java/io/netty/handler/execution/package-info.java @@ -21,6 +21,6 @@ * @apiviz.exclude ^java\.lang\. * @apiviz.exclude \.netty\.channel\. * @apiviz.exclude \.ExternalResourceReleasable$ - * @apiviz.exclude \.ChannelEventRunnable$ + * @apiviz.exclude \.Channel[A-Za-z]*EventRunnable[A-Za-z]*$ */ package io.netty.handler.execution; diff --git a/handler/src/main/java/io/netty/handler/ipfilter/CIDR.java b/handler/src/main/java/io/netty/handler/ipfilter/CIDR.java new file mode 100644 index 0000000000..b0a4857daa --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/CIDR.java @@ -0,0 +1,234 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.StringTokenizer; + +/** + */ +public abstract class CIDR implements Comparable { + /** The base address of the CIDR notation */ + protected InetAddress baseAddress; + + /** The mask used in the CIDR notation */ + protected int cidrMask; + + /** + * Create CIDR using the CIDR Notation + * + * @return the generated CIDR + */ + public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException { + if (cidrMask < 0) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + if (baseAddress instanceof Inet4Address) { + if (cidrMask > 32) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + return new CIDR4((Inet4Address) baseAddress, cidrMask); + } + // IPv6. + if (cidrMask > 128) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + return new CIDR6((Inet6Address) baseAddress, cidrMask); + } + + /** + * Create CIDR using the normal Notation + * + * @return the generated CIDR + */ + public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException { + int cidrMask = getNetMask(scidrMask); + if (cidrMask < 0) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + if (baseAddress instanceof Inet4Address) { + if (cidrMask > 32) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + return new CIDR4((Inet4Address) baseAddress, cidrMask); + } + cidrMask += 96; + // IPv6. + if (cidrMask > 128) { + throw new UnknownHostException("Invalid mask length used: " + cidrMask); + } + return new CIDR6((Inet6Address) baseAddress, cidrMask); + } + + /** + * Create CIDR using the CIDR or normal Notation
+ * i.e.: + * CIDR subnet = newCIDR ("10.10.10.0/24"); or + * CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or + * CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0"); + * + * @return the generated CIDR + */ + public static CIDR newCIDR(String cidr) throws UnknownHostException { + int p = cidr.indexOf("/"); + if (p < 0) { + throw new UnknownHostException("Invalid CIDR notation used: " + cidr); + } + String addrString = cidr.substring(0, p); + String maskString = cidr.substring(p + 1); + InetAddress addr = addressStringToInet(addrString); + int mask = 0; + if (maskString.indexOf(".") < 0) { + mask = parseInt(maskString, -1); + } else { + mask = getNetMask(maskString); + if (addr instanceof Inet6Address) { + mask += 96; + } + } + if (mask < 0) { + throw new UnknownHostException("Invalid mask length used: " + maskString); + } + return newCIDR(addr, mask); + } + + /** @return the baseAddress of the CIDR block. */ + public InetAddress getBaseAddress() { + return baseAddress; + } + + /** @return the Mask length. */ + public int getMask() { + return cidrMask; + } + + /** @return the textual CIDR notation. */ + @Override + public String toString() { + return baseAddress.getHostAddress() + "/" + cidrMask; + } + + /** @return the end address of this block. */ + public abstract InetAddress getEndAddress(); + + /** + * Compares the given InetAddress against the CIDR and returns true if + * the ip is in the subnet-ip-range and false if not. + * + * @return returns true if the given IP address is inside the currently + * set network. + */ + public abstract boolean contains(InetAddress inetAddress); + + @Override + public boolean equals(Object arg0) { + if (!(arg0 instanceof CIDR)) { + return false; + } + return this.compareTo((CIDR) arg0) == 0; + } + + @Override + public int hashCode() { + return baseAddress.hashCode(); + } + + /** + * Convert an IPv4 or IPv6 textual representation into an + * InetAddress. + * + * @return the created InetAddress + */ + private static InetAddress addressStringToInet(String addr) throws UnknownHostException { + return InetAddress.getByName(addr); + } + + /** + * Get the Subnet's Netmask in Decimal format.
+ * i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask + * + * @param netMask a network mask + * @return the integer CIDR mask + */ + private static int getNetMask(String netMask) { + StringTokenizer nm = new StringTokenizer(netMask, "."); + int i = 0; + int[] netmask = new int[4]; + while (nm.hasMoreTokens()) { + netmask[i] = Integer.parseInt(nm.nextToken()); + i++; + } + int mask1 = 0; + for (i = 0; i < 4; i++) { + mask1 += Integer.bitCount(netmask[i]); + } + return mask1; + } + + /** + * @param intstr a string containing an integer. + * @param def the default if the string does not contain a valid + * integer. + * @return the inetAddress from the integer + */ + private static int parseInt(String intstr, int def) { + Integer res; + if (intstr == null) { + return def; + } + try { + res = Integer.decode(intstr); + } catch (Exception e) { + res = new Integer(def); + } + return res.intValue(); + } + + /** + * Compute a byte representation of IpV4 from a IpV6 + * + * @return the byte representation + * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 + */ + public static byte[] getIpV4FromIpV6(Inet6Address address) { + byte[] baddr = address.getAddress(); + for (int i = 0; i < 9; i++) { + if (baddr[i] != 0) { + throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); + } + } + if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF) { + throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); + } + return new byte[] + {baddr[12], baddr[13], baddr[14], baddr[15]}; + } + + /** + * Compute a byte representation of IpV6 from a IpV4 + * + * @return the byte representation + * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 + */ + public static byte[] getIpV6FromIpV4(Inet4Address address) { + byte[] baddr = address.getAddress(); + return new byte[] + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]}; + } +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/CIDR4.java b/handler/src/main/java/io/netty/handler/ipfilter/CIDR4.java new file mode 100644 index 0000000000..1a4bc458b5 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/CIDR4.java @@ -0,0 +1,159 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + */ +public class CIDR4 extends CIDR { + /** The integer for the base address */ + private int addressInt; + + /** The integer for the end address */ + private final int addressEndInt; + + /** + * @param newaddr + * @param mask + */ + protected CIDR4(Inet4Address newaddr, int mask) { + cidrMask = mask; + addressInt = ipv4AddressToInt(newaddr); + int newmask = ipv4PrefixLengthToMask(mask); + addressInt &= newmask; + try { + baseAddress = intToIPv4Address(addressInt); + } catch (UnknownHostException e) { + // this should never happen + } + addressEndInt = addressInt + ipv4PrefixLengthToLength(cidrMask) - 1; + } + + @Override + public InetAddress getEndAddress() { + try { + return intToIPv4Address(addressEndInt); + } catch (UnknownHostException e) { + // this should never happen + return null; + } + } + + @Override + public int compareTo(CIDR arg) { + if (arg instanceof CIDR6) { + byte[] address = getIpV4FromIpV6((Inet6Address) arg.baseAddress); + int net = ipv4AddressToInt(address); + if (net == addressInt && arg.cidrMask == cidrMask) { + return 0; + } + if (net < addressInt) { + return 1; + } else if (net > addressInt) { + return -1; + } else if (arg.cidrMask < cidrMask) { + return -1; + } + return 1; + } + CIDR4 o = (CIDR4) arg; + if (o.addressInt == addressInt && o.cidrMask == cidrMask) { + return 0; + } + if (o.addressInt < addressInt) { + return 1; + } else if (o.addressInt > addressInt) { + return -1; + } else if (o.cidrMask < cidrMask) { + // greater Mask means less IpAddresses so -1 + return -1; + } + return 1; + } + + @Override + public boolean contains(InetAddress inetAddress) { + int search = ipv4AddressToInt(inetAddress); + return search >= addressInt && search <= addressEndInt; + } + + /** + * Given an IPv4 baseAddress length, return the block length. I.e., a + * baseAddress length of 24 will return 256. + */ + private static int ipv4PrefixLengthToLength(int prefix_length) { + return 1 << 32 - prefix_length; + } + + /** + * Given a baseAddress length, return a netmask. I.e, a baseAddress length + * of 24 will return 0xFFFFFF00. + */ + private static int ipv4PrefixLengthToMask(int prefix_length) { + return ~((1 << 32 - prefix_length) - 1); + } + + /** + * Convert an integer into an (IPv4) InetAddress. + * + * @return the created InetAddress + */ + private static InetAddress intToIPv4Address(int addr) throws UnknownHostException { + byte[] a = new byte[4]; + a[0] = (byte) (addr >> 24 & 0xFF); + a[1] = (byte) (addr >> 16 & 0xFF); + a[2] = (byte) (addr >> 8 & 0xFF); + a[3] = (byte) (addr & 0xFF); + return InetAddress.getByAddress(a); + } + + /** + * Given an IPv4 address, convert it into an integer. + * + * @return the integer representation of the InetAddress + * @throws IllegalArgumentException if the address is really an + * IPv6 address. + */ + private static int ipv4AddressToInt(InetAddress addr) { + byte[] address = null; + if (addr instanceof Inet6Address) { + address = getIpV4FromIpV6((Inet6Address) addr); + } else { + address = addr.getAddress(); + } + return ipv4AddressToInt(address); + } + + /** + * Given an IPv4 address as array of bytes, convert it into an integer. + * + * @return the integer representation of the InetAddress + * @throws IllegalArgumentException if the address is really an + * IPv6 address. + */ + private static int ipv4AddressToInt(byte[] address) { + int net = 0; + for (byte addres : address) { + net <<= 8; + net |= addres & 0xFF; + } + return net; + } +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/CIDR6.java b/handler/src/main/java/io/netty/handler/ipfilter/CIDR6.java new file mode 100644 index 0000000000..2ee9c7bd29 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/CIDR6.java @@ -0,0 +1,162 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +/** + */ +public class CIDR6 extends CIDR { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class); + + /** The big integer for the base address */ + private BigInteger addressBigInt; + + /** The big integer for the end address */ + private final BigInteger addressEndBigInt; + + /** + * @param newaddress + * @param newmask + */ + protected CIDR6(Inet6Address newaddress, int newmask) { + cidrMask = newmask; + addressBigInt = ipv6AddressToBigInteger(newaddress); + BigInteger mask = ipv6CidrMaskToMask(newmask); + try { + addressBigInt = addressBigInt.and(mask); + baseAddress = bigIntToIPv6Address(addressBigInt); + } catch (UnknownHostException e) { + // this should never happen. + } + addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE); + } + + @Override + public InetAddress getEndAddress() { + try { + return bigIntToIPv6Address(addressEndBigInt); + } catch (UnknownHostException e) { + logger.error("invalid ip address calculated as an end address"); + return null; + } + } + + @Override + public int compareTo(CIDR arg) { + if (arg instanceof CIDR4) { + BigInteger net = ipv6AddressToBigInteger(arg.baseAddress); + int res = net.compareTo(addressBigInt); + if (res == 0) { + if (arg.cidrMask == cidrMask) { + return 0; + } else if (arg.cidrMask < cidrMask) { + return -1; + } + return 1; + } + return res; + } + CIDR6 o = (CIDR6) arg; + if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask) { + return 0; + } + int res = o.addressBigInt.compareTo(addressBigInt); + if (res == 0) { + if (o.cidrMask < cidrMask) { + // greater Mask means less IpAddresses so -1 + return -1; + } + return 1; + } + return res; + } + + @Override + public boolean contains(InetAddress inetAddress) { + BigInteger search = ipv6AddressToBigInteger(inetAddress); + return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0; + } + + /** + * Given an IPv6 baseAddress length, return the block length. I.e., a + * baseAddress length of 96 will return 2**32. + */ + private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask) { + return BigInteger.ONE.shiftLeft(128 - cidrMask); + } + + private static BigInteger ipv6CidrMaskToMask(int cidrMask) { + return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not(); + } + + /** + * Given an IPv6 address, convert it into a BigInteger. + * + * @return the integer representation of the InetAddress + * @throws IllegalArgumentException if the address is not an IPv6 + * address. + */ + private static BigInteger ipv6AddressToBigInteger(InetAddress addr) { + byte[] ipv6; + if (addr instanceof Inet4Address) { + ipv6 = getIpV6FromIpV4((Inet4Address) addr); + } else { + ipv6 = addr.getAddress(); + } + if (ipv6[0] == -1) { + return new BigInteger(1, ipv6); + } + return new BigInteger(ipv6); + } + + /** + * Convert a big integer into an IPv6 address. + * + * @return the inetAddress from the integer + * @throws UnknownHostException if the big integer is too large, + * and thus an invalid IPv6 address. + */ + private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException { + byte[] a = new byte[16]; + byte[] b = addr.toByteArray(); + if (b.length > 16 && !(b.length == 17 && b[0] == 0)) { + throw new UnknownHostException("invalid IPv6 address (too big)"); + } + if (b.length == 16) { + return InetAddress.getByAddress(b); + } + // handle the case where the IPv6 address starts with "FF". + if (b.length == 17) { + System.arraycopy(b, 1, a, 0, 16); + } else { + // copy the address into a 16 byte array, zero-filled. + int p = 16 - b.length; + for (int i = 0; i < b.length; i++) { + a[p + i] = b[i]; + } + } + return InetAddress.getByAddress(a); + } +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java new file mode 100644 index 0000000000..2ae727508a --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java @@ -0,0 +1,67 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetSocketAddress; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; + +/** + * The listener interface for receiving ipFilter events. + * + * @see IpFilteringHandler + */ +public interface IpFilterListener { + + /** + * Called when the channel has the CONNECTED status and the channel was allowed by a previous call to accept(). + * This method enables your implementation to send a message back to the client before closing + * or whatever you need. This method returns a ChannelFuture on which the implementation + * can wait uninterruptibly before continuing.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. + * + * @param inetSocketAddress the remote {@link InetSocketAddress} from client + * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. + */ + ChannelFuture allowed(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); + + /** + * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). + * This method enables your implementation to send a message back to the client before closing + * or whatever you need. This method returns a ChannelFuture on which the implementation + * will wait uninterruptibly before closing the channel.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. + * + * @param inetSocketAddress the remote {@link InetSocketAddress} from client + * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. + */ + ChannelFuture refused(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); + + /** + * Called in handleUpstream, if this channel was previously blocked, + * to check if whatever the event, it should be passed to the next entry in the pipeline.
+ * If one wants to not block events, just overridden this method by returning always true.

+ * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since + * those events come out before the CONNECTED event and so the possibility to filter the connection. + * + * @return True if the event should continue, False if the event should not continue + * since this channel was blocked by this filter + */ + boolean continues(ChannelHandlerContext ctx, ChannelEvent e); + +} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java similarity index 70% rename from src/main/java/io/netty/handler/ipfilter/IpFilterRule.java rename to handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java index 322670d3cf..31e540c7a3 100644 --- a/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRule.java @@ -15,20 +15,11 @@ */ package io.netty.handler.ipfilter; -/** - * This Interface defines an Ip Filter Rule. - */ -public interface IpFilterRule extends IpSet -{ - /** - * - * @return True if this Rule is an ALLOW rule - */ - boolean isAllowRule(); +/** This Interface defines an Ip Filter Rule. */ +public interface IpFilterRule extends IpSet { + /** @return True if this Rule is an ALLOW rule */ + boolean isAllowRule(); - /** - * - * @return True if this Rule is a DENY rule - */ - boolean isDenyRule(); + /** @return True if this Rule is a DENY rule */ + boolean isDenyRule(); } diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java new file mode 100644 index 0000000000..edb6cc9206 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java @@ -0,0 +1,259 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; + +/** + * Implementation of Filter of IP based on ALLOW and DENY rules.
+ *

+ * This implementation could be changed by implementing a new {@link IpFilterRule} than default + * {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) or {@link IpFilterRule} (IP and host name string pattern support) .
+ *
+ * The check is done by going from step to step in the underlying array of IpFilterRule.
+ * Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not, + * according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall + * usual rules, the InetAddress is therefore accepted by default.
+ *
    + *
  • If it was constructed with True as first argument, + * the IpFilterRule is an ALLOW rule (every InetAddress that fits in the rule will be accepted).
  • + *
  • If it was constructed with False as first argument, + * the IpFilterRule is a DENY rule (every InetAddress that fits in the rule will be refused).
  • + *

+ *
+ * An empty list means allow all (no limitation).

+ * For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler. + * You should prefer to replace an entry (set method) with an ALLOW/DENY ALL IpFilterRule + * if possible.


+ * This handler should be created only once and reused on every pipeline since it handles + * a global status of what is allowed or blocked.

+ *

+ * Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as + * possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation + * and the address from the channel in IPV4, or the reverse) can lead to wrong result. + */ +@Sharable +public class IpFilterRuleHandler extends IpFilteringHandlerImpl { + /** List of {@link IpFilterRule} */ + private final CopyOnWriteArrayList ipFilterRuleList = new CopyOnWriteArrayList(); + + /** Constructor from a new list of IpFilterRule */ + public IpFilterRuleHandler(List newList) { + if (newList != null) { + ipFilterRuleList.addAll(newList); + } + } + + /** + * Empty constructor (no IpFilterRule in the List at construction). In such a situation, + * empty list implies allow all. + */ + public IpFilterRuleHandler() { + } + + // Below are methods directly inspired from CopyOnWriteArrayList methods + + /** Add an ipFilterRule in the list at the end */ + public void add(IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + ipFilterRuleList.add(ipFilterRule); + } + + /** Add an ipFilterRule in the list at the specified position (shifting to the right other elements) */ + public void add(int index, IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + ipFilterRuleList.add(index, ipFilterRule); + } + + /** + * Appends all of the elements in the specified collection to the end of this list, + * in the order that they are returned by the specified collection's iterator. + */ + public void addAll(Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + ipFilterRuleList.addAll(c); + } + + /** Inserts all of the elements in the specified collection into this list, starting at the specified position. */ + public void addAll(int index, Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + ipFilterRuleList.addAll(index, c); + } + + /** + * Append the element if not present. + * + * @return the number of elements added + */ + public int addAllAbsent(Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + return ipFilterRuleList.addAllAbsent(c); + } + + /** + * Append the element if not present. + * + * @return true if the element was added + */ + public boolean addIfAbsent(IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + return ipFilterRuleList.addIfAbsent(ipFilterRule); + } + + /** Clear the list */ + public void clear() { + ipFilterRuleList.clear(); + } + + /** + * Returns true if this list contains the specified element + * + * @return true if this list contains the specified element + */ + public boolean contains(IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + return ipFilterRuleList.contains(ipFilterRule); + } + + /** + * Returns true if this list contains all of the elements of the specified collection + * + * @return true if this list contains all of the elements of the specified collection + */ + public boolean containsAll(Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + return ipFilterRuleList.containsAll(c); + } + + /** + * Returns the element at the specified position in this list + * + * @return the element at the specified position in this list + */ + public IpFilterRule get(int index) { + return ipFilterRuleList.get(index); + } + + /** + * Returns true if this list contains no elements + * + * @return true if this list contains no elements + */ + public boolean isEmpty() { + return ipFilterRuleList.isEmpty(); + } + + /** Remove the ipFilterRule from the list */ + public void remove(IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + ipFilterRuleList.remove(ipFilterRule); + } + + /** + * Removes the element at the specified position in this list + * + * @return the element previously at the specified position + */ + public IpFilterRule remove(int index) { + return ipFilterRuleList.remove(index); + } + + /** Removes from this list all of its elements that are contained in the specified collection */ + public void removeAll(Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + ipFilterRuleList.removeAll(c); + } + + /** Retains only the elements in this list that are contained in the specified collection */ + public void retainAll(Collection c) { + if (c == null) { + throw new NullPointerException("Collection can not be null"); + } + ipFilterRuleList.retainAll(c); + } + + /** + * Replaces the element at the specified position in this list with the specified element + * + * @return the element previously at the specified position + */ + public IpFilterRule set(int index, IpFilterRule ipFilterRule) { + if (ipFilterRule == null) { + throw new NullPointerException("IpFilterRule can not be null"); + } + return ipFilterRuleList.set(index, ipFilterRule); + } + + /** + * Returns the number of elements in this list. + * + * @return the number of elements in this list. + */ + public int size() { + return ipFilterRuleList.size(); + } + + @Override + protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) + throws Exception { + if (ipFilterRuleList.isEmpty()) { + // No limitation neither in deny or allow, so accept + return true; + } + InetAddress inetAddress = inetSocketAddress.getAddress(); + Iterator iterator = ipFilterRuleList.iterator(); + IpFilterRule ipFilterRule = null; + while (iterator.hasNext()) { + ipFilterRule = iterator.next(); + if (ipFilterRule.contains(inetAddress)) { + // Match founds, is it a ALLOW or DENY rule + return ipFilterRule.isAllowRule(); + } + } + // No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted + return true; + } + +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java new file mode 100644 index 0000000000..020c35aeae --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java @@ -0,0 +1,89 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.UnknownHostException; +import java.util.ArrayList; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +/** + * The Class IpFilterRuleList is a helper class to generate a List of Rules from a string. + * In case of parse errors no exceptions are thrown. The error is logged. + *
+ * Rule List Syntax: + *
+ *

+ * RuleList ::= Rule[,Rule]*
+ * Rule ::= AllowRule | BlockRule
+ * AllowRule ::= +Filter
+ * BlockRule ::= -Filter
+ * Filter ::= PatternFilter | CIDRFilter
+ * PatternFilter ::= @see PatternRule
+ * CIDRFilter ::= c:CIDRFilter
+ * CIDRFilter ::= @see CIDR.newCIDR(String)
+ * 
+ *
+ * Example: allow only localhost: + *
+ * new IPFilterRuleHandler().addAll(new IpFilterRuleList("+n:localhost, -n:*")); + *
+ */ +public class IpFilterRuleList extends ArrayList { + private static final long serialVersionUID = -6164162941749588780L; + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpFilterRuleList.class); + + /** + * Instantiates a new ip filter rule list. + * + * @param rules the rules + */ + public IpFilterRuleList(String rules) { + parseRules(rules); + } + + private void parseRules(String rules) { + String[] ruless = rules.split(","); + for (String rule : ruless) { + parseRule(rule.trim()); + } + } + + private void parseRule(String rule) { + if (rule == null || rule.length() == 0) { + return; + } + if (!(rule.startsWith("+") || rule.startsWith("-"))) { + logger.error("syntax error in ip filter rule:" + rule); + return; + } + + boolean allow = rule.startsWith("+"); + if (rule.charAt(1) == 'n' || rule.charAt(1) == 'i') { + this.add(new PatternRule(allow, rule.substring(1))); + } else if (rule.charAt(1) == 'c') { + try { + this.add(new IpSubnetFilterRule(allow, rule.substring(3))); + } catch (UnknownHostException e) { + logger.error("error parsing ip filter " + rule, e); + } + } else { + logger.error("syntax error in ip filter rule:" + rule); + } + } +} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java similarity index 75% rename from src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java rename to handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java index 08f5f455a7..0d04ef1ce3 100644 --- a/src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandler.java @@ -21,18 +21,15 @@ package io.netty.handler.ipfilter; *
* Users can add an {@link IpFilterListener} to add specific actions in case a connection is allowed or refused. */ -public interface IpFilteringHandler -{ - - /** - * Sets the filter listener. - * - * @param listener the new ip filter listener - */ - void setIpFilterListener(IpFilterListener listener); +public interface IpFilteringHandler { - /** - * Remove the filter listener. - */ - void removeIpFilterListener(); + /** + * Sets the filter listener. + * + * @param listener the new ip filter listener + */ + void setIpFilterListener(IpFilterListener listener); + + /** Remove the filter listener. */ + void removeIpFilterListener(); } diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java b/handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java new file mode 100644 index 0000000000..b9d0c805ff --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java @@ -0,0 +1,164 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetSocketAddress; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.ChannelUpstreamHandler; +import io.netty.channel.Channels; + +// TODO: Auto-generated Javadoc + +/** General class that handle Ip Filtering. */ +public abstract class IpFilteringHandlerImpl implements ChannelUpstreamHandler, IpFilteringHandler { + + private IpFilterListener listener; + + /** + * Called when the channel is connected. It returns True if the corresponding connection + * is to be allowed. Else it returns False. + * + * @param inetSocketAddress the remote {@link InetSocketAddress} from client + * @return True if the corresponding connection is allowed, else False. + */ + protected abstract boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) + throws Exception; + + /** + * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). + * This method enables your implementation to send a message back to the client before closing + * or whatever you need. This method returns a ChannelFuture on which the implementation + * will wait uninterruptibly before closing the channel.
+ * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. + * + * @param inetSocketAddress the remote {@link InetSocketAddress} from client + * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. + */ + protected ChannelFuture handleRefusedChannel(ChannelHandlerContext ctx, ChannelEvent e, + InetSocketAddress inetSocketAddress) throws Exception { + if (listener == null) { + return null; + } + return listener.refused(ctx, e, inetSocketAddress); + } + + protected ChannelFuture handleAllowedChannel(ChannelHandlerContext ctx, ChannelEvent e, + InetSocketAddress inetSocketAddress) throws Exception { + if (listener == null) { + return null; + } + return listener.allowed(ctx, e, inetSocketAddress); + } + + /** + * Internal method to test if the current channel is blocked. Should not be overridden. + * + * @return True if the current channel is blocked, else False + */ + protected boolean isBlocked(ChannelHandlerContext ctx) { + return ctx.getAttachment() != null; + } + + /** + * Called in handleUpstream, if this channel was previously blocked, + * to check if whatever the event, it should be passed to the next entry in the pipeline.
+ * If one wants to not block events, just overridden this method by returning always true.

+ * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since + * those events come out before the CONNECTED event and so the possibility to filter the connection. + * + * @return True if the event should continue, False if the event should not continue + * since this channel was blocked by this filter + */ + protected boolean continues(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { + if (listener != null) { + return listener.continues(ctx, e); + } else { + return false; + } + } + + @Override + public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { + if (e instanceof ChannelStateEvent) { + ChannelStateEvent evt = (ChannelStateEvent) e; + switch (evt.getState()) { + case OPEN: + case BOUND: + // Special case: OPEND and BOUND events are before CONNECTED, + // but CLOSED and UNBOUND events are after DISCONNECTED: should those events be blocked too? + if (isBlocked(ctx) && !continues(ctx, evt)) { + // don't pass to next level since channel was blocked early + return; + } else { + ctx.sendUpstream(e); + return; + } + case CONNECTED: + if (evt.getValue() != null) { + // CONNECTED + InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); + if (!accept(ctx, e, inetSocketAddress)) { + ctx.setAttachment(Boolean.TRUE); + ChannelFuture future = handleRefusedChannel(ctx, e, inetSocketAddress); + if (future != null) { + future.addListener(ChannelFutureListener.CLOSE); + } else { + Channels.close(e.getChannel()); + } + if (isBlocked(ctx) && !continues(ctx, evt)) { + // don't pass to next level since channel was blocked early + return; + } + } else { + handleAllowedChannel(ctx, e, inetSocketAddress); + } + // This channel is not blocked + ctx.setAttachment(null); + } else { + // DISCONNECTED + if (isBlocked(ctx) && !continues(ctx, evt)) { + // don't pass to next level since channel was blocked early + return; + } + } + break; + } + } + if (isBlocked(ctx) && !continues(ctx, e)) { + // don't pass to next level since channel was blocked early + return; + } + // Whatever it is, if not blocked, goes to the next level + ctx.sendUpstream(e); + } + + @Override + public void setIpFilterListener(IpFilterListener listener) { + this.listener = listener; + } + + @Override + public void removeIpFilterListener() { + this.listener = null; + + } + +} diff --git a/src/main/java/io/netty/handler/ipfilter/IpSet.java b/handler/src/main/java/io/netty/handler/ipfilter/IpSet.java similarity index 63% rename from src/main/java/io/netty/handler/ipfilter/IpSet.java rename to handler/src/main/java/io/netty/handler/ipfilter/IpSet.java index a734975e7a..6689480c06 100644 --- a/src/main/java/io/netty/handler/ipfilter/IpSet.java +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpSet.java @@ -17,17 +17,14 @@ package io.netty.handler.ipfilter; import java.net.InetAddress; -/** - * This Interface defines an IpSet object. - */ -public interface IpSet -{ - /** - * Compares the given InetAddress against the IpSet and returns true if - * the InetAddress is contained in this Rule and false if not. - * @param inetAddress1 - * @return returns true if the given IP address is contained in the current - * IpSet. - */ - boolean contains(InetAddress inetAddress1); +/** This Interface defines an IpSet object. */ +public interface IpSet { + /** + * Compares the given InetAddress against the IpSet and returns true if + * the InetAddress is contained in this Rule and false if not. + * + * @return returns true if the given IP address is contained in the current + * IpSet. + */ + boolean contains(InetAddress inetAddress1); } diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpSubnet.java b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnet.java new file mode 100644 index 0000000000..251fefb3dc --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnet.java @@ -0,0 +1,162 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * This class allows to check if an IP V4 or V6 Address is contained in a subnet.
+ *

+ * Supported IP V4 Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) + * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
+ *

Example1:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *

Example2:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example2 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *
+ * Supported IP V6 Formats for the Subnets are: a:b:c:d:e:f:g:h/NN (CIDR-Notation) + * or any IPV6 notations (like a:b:c:d::/NN, a:b:c:d:e:f:w.x.y.z/NN) + * and (InetAddress,Mask) where Mask is a integer for CIDR-notation + * and (InetAddress,subnet).
+ *

Example1:
+ * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
+ * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3::/24");
+ * System.out.println("Result: "+ ips.contains("1fff:0:0a88:85a3:0:0:ac1f:8001"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpSubnet ips = new IpSubnet(inetAddress, 24);
+ * where inetAddress2 is 1fff:0:0a88:85a3:0:0:ac1f:8001
+ */ +public class IpSubnet implements IpSet, Comparable { + /** Internal representation */ + private CIDR cidr; + + /** Create IpSubnet for ALL (used for ALLOW or DENY ALL) */ + public IpSubnet() { + // ALLOW or DENY ALL + cidr = null; + } + + /** + * Create IpSubnet using the CIDR or normal Notation
+ * i.e.:
+ * IpSubnet subnet = new IpSubnet("10.10.10.0/24"); or
+ * IpSubnet subnet = new IpSubnet("10.10.10.0/255.255.255.0"); or
+ * IpSubnet subnet = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24"); + * + * @param netAddress a network address as string. + */ + public IpSubnet(String netAddress) throws UnknownHostException { + cidr = CIDR.newCIDR(netAddress); + } + + /** Create IpSubnet using the CIDR Notation */ + public IpSubnet(InetAddress inetAddress, int cidrNetMask) throws UnknownHostException { + cidr = CIDR.newCIDR(inetAddress, cidrNetMask); + } + + /** Create IpSubnet using the normal Notation */ + public IpSubnet(InetAddress inetAddress, String netMask) throws UnknownHostException { + cidr = CIDR.newCIDR(inetAddress, netMask); + } + + /** + * Compares the given IP-Address against the Subnet and returns true if + * the ip is in the subnet-ip-range and false if not. + * + * @param ipAddr an ipaddress + * @return returns true if the given IP address is inside the currently + * set network. + */ + public boolean contains(String ipAddr) throws UnknownHostException { + InetAddress inetAddress1 = InetAddress.getByName(ipAddr); + return this.contains(inetAddress1); + } + + /** + * Compares the given InetAddress against the Subnet and returns true if + * the ip is in the subnet-ip-range and false if not. + * + * @return returns true if the given IP address is inside the currently + * set network. + */ + @Override + public boolean contains(InetAddress inetAddress) { + if (cidr == null) { + // ANY + return true; + } + return cidr.contains(inetAddress); + } + + @Override + public String toString() { + return cidr.toString(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpSubnet)) { + return false; + } + IpSubnet ipSubnet = (IpSubnet) o; + return ipSubnet.cidr.equals(cidr); + } + + @Override + public int hashCode() { + return cidr.hashCode(); + } + + /** Compare two IpSubnet */ + @Override + public int compareTo(IpSubnet o) { + return cidr.toString().compareTo(o.cidr.toString()); + } + + /** + * Simple test functions + * + * @param args where args[0] is the netmask (standard or CIDR notation) and optional args[1] is + * the inetAddress to test with this IpSubnet + */ + public static void main(String[] args) throws Exception { + if (args.length != 0) { + IpSubnet ipSubnet = null; + try { + ipSubnet = new IpSubnet(args[0]); + } catch (UnknownHostException e) { + return; + } + System.out.println("IpSubnet: " + ipSubnet.toString() + " from " + ipSubnet.cidr.getBaseAddress() + " to " + + ipSubnet.cidr.getEndAddress() + " mask " + ipSubnet.cidr.getMask()); + if (args.length > 1) { + System.out.println("Is IN: " + args[1] + " " + ipSubnet.contains(args[1])); + } + } + } +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java new file mode 100644 index 0000000000..162a74f409 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java @@ -0,0 +1,68 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Ip V4 and Ip V6 filter rule.
+ *
+ * Note that mix of IPV4 and IPV6 is allowed but it is not recommended. So it is preferable to not + * mix IPV4 addresses with IPV6 rules, even if it should work. + */ +public class IpSubnetFilterRule extends IpSubnet implements IpFilterRule { + /** Is this IpV4Subnet an ALLOW or DENY rule */ + private boolean isAllowRule = true; + + /** + * Constructor for a ALLOW or DENY ALL + * + * @param allow True for ALLOW, False for DENY + */ + public IpSubnetFilterRule(boolean allow) { + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) throws UnknownHostException { + super(inetAddress, cidrNetMask); + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) throws UnknownHostException { + super(inetAddress, netMask); + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpSubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException { + super(netAddress); + isAllowRule = allow; + } + + @Override + public boolean isAllowRule() { + return isAllowRule; + } + + @Override + public boolean isDenyRule() { + return !isAllowRule; + } + +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java b/handler/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java new file mode 100644 index 0000000000..71d6837e5d --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java @@ -0,0 +1,270 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * This class allows to check if an IP-V4-Address is contained in a subnet.
+ * Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) + * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
+ *

Example1:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example1 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ *

Example2:
+ * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
+ * System.out.println("Result: "+ ips.contains("192.168.1.123"));
+ * System.out.println("Result: "+ ips.contains(inetAddress2));
+ *
Example2 bis:
+ * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
+ * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
+ */ +public class IpV4Subnet implements IpSet, Comparable { + private static final int SUBNET_MASK = 0x80000000; + + private static final int BYTE_ADDRESS_MASK = 0xFF; + + private InetAddress inetAddress; + + private int subnet; + + private int mask; + + private int cidrMask; + + /** Create IpV4Subnet for ALL (used for ALLOW or DENY ALL) */ + public IpV4Subnet() { + // ALLOW or DENY ALL + mask = -1; + // other will be ignored + inetAddress = null; + subnet = 0; + cidrMask = 0; + } + + /** + * Create IpV4Subnet using the CIDR or normal Notation
+ * i.e.: + * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or + * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0"); + * + * @param netAddress a network address as string. + */ + public IpV4Subnet(String netAddress) throws UnknownHostException { + setNetAddress(netAddress); + } + + /** Create IpV4Subnet using the CIDR Notation */ + public IpV4Subnet(InetAddress inetAddress, int cidrNetMask) { + setNetAddress(inetAddress, cidrNetMask); + } + + /** Create IpV4Subnet using the normal Notation */ + public IpV4Subnet(InetAddress inetAddress, String netMask) { + setNetAddress(inetAddress, netMask); + } + + /** + * Sets the Network Address in either CIDR or Decimal Notation.
+ * i.e.: setNetAddress("1.1.1.1/24"); or
+ * setNetAddress("1.1.1.1/255.255.255.0");
+ * + * @param netAddress a network address as string. + */ + private void setNetAddress(String netAddress) throws UnknownHostException { + Vector vec = new Vector(); + StringTokenizer st = new StringTokenizer(netAddress, "/"); + while (st.hasMoreTokens()) { + vec.add(st.nextElement()); + } + + if (vec.get(1).toString().length() < 3) { + setNetId(vec.get(0).toString()); + setCidrNetMask(Integer.parseInt(vec.get(1).toString())); + } else { + setNetId(vec.get(0).toString()); + setNetMask(vec.get(1).toString()); + } + } + + /** Sets the Network Address in CIDR Notation. */ + private void setNetAddress(InetAddress inetAddress, int cidrNetMask) { + setNetId(inetAddress); + setCidrNetMask(cidrNetMask); + } + + /** Sets the Network Address in Decimal Notation. */ + private void setNetAddress(InetAddress inetAddress, String netMask) { + setNetId(inetAddress); + setNetMask(netMask); + } + + /** + * Sets the BaseAdress of the Subnet.
+ * i.e.: setNetId("192.168.1.0"); + * + * @param netId a network ID + */ + private void setNetId(String netId) throws UnknownHostException { + InetAddress inetAddress1 = InetAddress.getByName(netId); + this.setNetId(inetAddress1); + } + + /** + * Compute integer representation of InetAddress + * + * @return the integer representation + */ + private int toInt(InetAddress inetAddress1) { + byte[] address = inetAddress1.getAddress(); + int net = 0; + for (byte addres : address) { + net <<= 8; + net |= addres & BYTE_ADDRESS_MASK; + } + return net; + } + + /** Sets the BaseAdress of the Subnet. */ + private void setNetId(InetAddress inetAddress) { + this.inetAddress = inetAddress; + subnet = toInt(inetAddress); + } + + /** + * Sets the Subnet's Netmask in Decimal format.
+ * i.e.: setNetMask("255.255.255.0"); + * + * @param netMask a network mask + */ + private void setNetMask(String netMask) { + StringTokenizer nm = new StringTokenizer(netMask, "."); + int i = 0; + int[] netmask = new int[4]; + while (nm.hasMoreTokens()) { + netmask[i] = Integer.parseInt(nm.nextToken()); + i++; + } + int mask1 = 0; + for (i = 0; i < 4; i++) { + mask1 += Integer.bitCount(netmask[i]); + } + setCidrNetMask(mask1); + } + + /** + * Sets the CIDR Netmask
+ * i.e.: setCidrNetMask(24); + * + * @param cidrNetMask a netmask in CIDR notation + */ + private void setCidrNetMask(int cidrNetMask) { + cidrMask = cidrNetMask; + mask = SUBNET_MASK >> cidrMask - 1; + } + + /** + * Compares the given IP-Address against the Subnet and returns true if + * the ip is in the subnet-ip-range and false if not. + * + * @param ipAddr an ipaddress + * @return returns true if the given IP address is inside the currently + * set network. + */ + public boolean contains(String ipAddr) throws UnknownHostException { + InetAddress inetAddress1 = InetAddress.getByName(ipAddr); + return this.contains(inetAddress1); + } + + /** + * Compares the given InetAddress against the Subnet and returns true if + * the ip is in the subnet-ip-range and false if not. + * + * @return returns true if the given IP address is inside the currently + * set network. + */ + @Override + public boolean contains(InetAddress inetAddress1) { + if (mask == -1) { + // ANY + return true; + } + return (toInt(inetAddress1) & mask) == subnet; + } + + @Override + public String toString() { + return inetAddress.getHostAddress() + "/" + cidrMask; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpV4Subnet)) { + return false; + } + IpV4Subnet ipV4Subnet = (IpV4Subnet) o; + return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask; + } + + @Override + public int hashCode() { + return subnet; + } + + /** Compare two IpV4Subnet */ + @Override + public int compareTo(IpV4Subnet o) { + if (o.subnet == subnet && o.cidrMask == cidrMask) { + return 0; + } + if (o.subnet < subnet) { + return 1; + } else if (o.subnet > subnet) { + return -1; + } else if (o.cidrMask < cidrMask) { + // greater Mask means less IpAddresses so -1 + return -1; + } + return 1; + } + + /** + * Simple test functions + * + * @param args where args[0] is the netmask (standard or CIDR notation) and optional args[1] is + * the inetAddress to test with this IpV4Subnet + */ + public static void main(String[] args) throws Exception { + if (args.length != 0) { + IpV4Subnet ipV4Subnet = null; + try { + ipV4Subnet = new IpV4Subnet(args[0]); + } catch (UnknownHostException e) { + return; + } + if (args.length > 1) { + System.out.println("Is IN: " + args[1] + " " + ipV4Subnet.contains(args[1])); + } + } + } +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java b/handler/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java new file mode 100644 index 0000000000..7d5511ff24 --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java @@ -0,0 +1,63 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** IpV4 only Filter Rule */ +public class IpV4SubnetFilterRule extends IpV4Subnet implements IpFilterRule { + /** Is this IpV4Subnet an ALLOW or DENY rule */ + private boolean isAllowRule = true; + + /** + * Constructor for a ALLOW or DENY ALL + * + * @param allow True for ALLOW, False for DENY + */ + public IpV4SubnetFilterRule(boolean allow) { + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) { + super(inetAddress, cidrNetMask); + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) { + super(inetAddress, netMask); + isAllowRule = allow; + } + + /** @param allow True for ALLOW, False for DENY */ + public IpV4SubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException { + super(netAddress); + isAllowRule = allow; + } + + @Override + public boolean isAllowRule() { + return isAllowRule; + } + + @Override + public boolean isDenyRule() { + return !isAllowRule; + } + +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java b/handler/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java new file mode 100644 index 0000000000..0f55e08dcb --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelState; +import io.netty.channel.ChannelStateEvent; + +/** + * Handler that block any new connection if there are already a currently active + * channel connected with the same InetAddress (IP).
+ *
+ *

+ * Take care to not change isBlocked method except if you know what you are doing + * since it is used to test if the current closed connection is to be removed + * or not from the map of currently connected channel. + */ +@Sharable +public class OneIpFilterHandler extends IpFilteringHandlerImpl { + /** HashMap of current remote connected InetAddress */ + private final ConcurrentMap connectedSet = new ConcurrentHashMap(); + + @Override + protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) + throws Exception { + InetAddress inetAddress = inetSocketAddress.getAddress(); + if (connectedSet.containsKey(inetAddress)) { + return false; + } + connectedSet.put(inetAddress, Boolean.TRUE); + return true; + } + + @Override + public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { + super.handleUpstream(ctx, e); + // Try to remove entry from Map if already exists + if (e instanceof ChannelStateEvent) { + ChannelStateEvent evt = (ChannelStateEvent) e; + if (evt.getState() == ChannelState.CONNECTED) { + if (evt.getValue() == null) { + // DISCONNECTED but was this channel blocked or not + if (isBlocked(ctx)) { + // remove inetsocketaddress from set since this channel was not blocked before + InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); + connectedSet.remove(inetSocketAddress.getAddress()); + } + } + } + } + } + +} diff --git a/handler/src/main/java/io/netty/handler/ipfilter/PatternRule.java b/handler/src/main/java/io/netty/handler/ipfilter/PatternRule.java new file mode 100644 index 0000000000..04d6be559b --- /dev/null +++ b/handler/src/main/java/io/netty/handler/ipfilter/PatternRule.java @@ -0,0 +1,198 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package io.netty.handler.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.regex.Pattern; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +/** + * The Class PatternRule represents an IP filter rule using string patterns. + *
+ * Rule Syntax: + *
+ *

+ * Rule ::= [n|i]:address          n stands for computer name, i for ip address
+ * address ::= <regex> | localhost
+ * regex is a regular expression with '*' as multi character and '?' as single character wild card
+ * 
+ *
+ * Example: allow localhost: + *
+ * new PatternRule(true, "n:localhost") + *
+ * Example: allow local lan: + *
+ * new PatternRule(true, "i:192.168.0.*") + *
+ * Example: block all + *
+ * new PatternRule(false, "n:*") + *
+ */ +public class PatternRule implements IpFilterRule, Comparable { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(PatternRule.class); + + private Pattern ipPattern; + + private Pattern namePattern; + + private boolean isAllowRule = true; + + private boolean localhost; + + private String pattern; + + /** + * Instantiates a new pattern rule. + * + * @param allow indicates if this is an allow or block rule + * @param pattern the filter pattern + */ + public PatternRule(boolean allow, String pattern) { + this.isAllowRule = allow; + this.pattern = pattern; + parse(pattern); + } + + /** + * returns the pattern. + * + * @return the pattern + */ + public String getPattern() { + return this.pattern; + } + + @Override + public boolean isAllowRule() { + return isAllowRule; + } + + @Override + public boolean isDenyRule() { + return !isAllowRule; + } + + @Override + public boolean contains(InetAddress inetAddress) { + if (localhost) { + if (isLocalhost(inetAddress)) { + return true; + } + } + if (ipPattern != null) { + if (ipPattern.matcher(inetAddress.getHostAddress()).matches()) { + return true; + } + } + if (namePattern != null) { + if (namePattern.matcher(inetAddress.getHostName()).matches()) { + return true; + } + } + return false; + } + + private void parse(String pattern) { + if (pattern == null) { + return; + } + + String[] acls = pattern.split(","); + + String ip = ""; + String name = ""; + for (String c : acls) { + c = c.trim(); + if (c.equals("n:localhost")) { + this.localhost = true; + } else if (c.startsWith("n:")) { + name = addRule(name, c.substring(2)); + } else if (c.startsWith("i:")) { + ip = addRule(ip, c.substring(2)); + } + } + if (ip.length() != 0) { + ipPattern = Pattern.compile(ip); + } + if (name.length() != 0) { + namePattern = Pattern.compile(name); + } + } + + private String addRule(String pattern, String rule) { + if (rule == null || rule.length() == 0) { + return pattern; + } + if (pattern.length() != 0) { + pattern += "|"; + } + rule = rule.replaceAll("\\.", "\\\\."); + rule = rule.replaceAll("\\*", ".*"); + rule = rule.replaceAll("\\?", "."); + pattern += "(" + rule + ")"; + return pattern; + } + + private boolean isLocalhost(InetAddress address) { + try { + if (address.equals(InetAddress.getLocalHost())) { + return true; + } + } catch (UnknownHostException e) { + logger.info("error getting ip of localhost", e); + } + try { + InetAddress[] addrs = InetAddress.getAllByName("127.0.0.1"); + for (InetAddress addr : addrs) { + if (addr.equals(address)) { + return true; + } + } + } catch (UnknownHostException e) { + logger.info("error getting ip of localhost", e); + } + return false; + + } + + @Override + public int compareTo(Object o) { + if (o == null) { + return -1; + } + if (!(o instanceof PatternRule)) { + return -1; + } + PatternRule p = (PatternRule) o; + if (p.isAllowRule() && !this.isAllowRule) { + return -1; + } + if (this.pattern == null && p.pattern == null) { + return 0; + } + if (this.pattern != null) { + return this.pattern.compareTo(p.getPattern()); + } + return -1; + } + +} diff --git a/src/main/java/io/netty/handler/ipfilter/package-info.java b/handler/src/main/java/io/netty/handler/ipfilter/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/ipfilter/package-info.java rename to handler/src/main/java/io/netty/handler/ipfilter/package-info.java diff --git a/src/main/java/io/netty/handler/logging/LoggingHandler.java b/handler/src/main/java/io/netty/handler/logging/LoggingHandler.java similarity index 100% rename from src/main/java/io/netty/handler/logging/LoggingHandler.java rename to handler/src/main/java/io/netty/handler/logging/LoggingHandler.java diff --git a/src/main/java/io/netty/handler/logging/package-info.java b/handler/src/main/java/io/netty/handler/logging/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/logging/package-info.java rename to handler/src/main/java/io/netty/handler/logging/package-info.java diff --git a/src/main/java/io/netty/handler/queue/BlockingReadHandler.java b/handler/src/main/java/io/netty/handler/queue/BlockingReadHandler.java similarity index 100% rename from src/main/java/io/netty/handler/queue/BlockingReadHandler.java rename to handler/src/main/java/io/netty/handler/queue/BlockingReadHandler.java diff --git a/src/main/java/io/netty/handler/queue/BlockingReadTimeoutException.java b/handler/src/main/java/io/netty/handler/queue/BlockingReadTimeoutException.java similarity index 100% rename from src/main/java/io/netty/handler/queue/BlockingReadTimeoutException.java rename to handler/src/main/java/io/netty/handler/queue/BlockingReadTimeoutException.java diff --git a/src/main/java/io/netty/handler/queue/BufferedWriteHandler.java b/handler/src/main/java/io/netty/handler/queue/BufferedWriteHandler.java similarity index 100% rename from src/main/java/io/netty/handler/queue/BufferedWriteHandler.java rename to handler/src/main/java/io/netty/handler/queue/BufferedWriteHandler.java diff --git a/src/main/java/io/netty/handler/queue/package-info.java b/handler/src/main/java/io/netty/handler/queue/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/queue/package-info.java rename to handler/src/main/java/io/netty/handler/queue/package-info.java diff --git a/src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java b/handler/src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java similarity index 95% rename from src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java rename to handler/src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java index 6c1b28305e..2fdaa3f901 100644 --- a/src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java +++ b/handler/src/main/java/io/netty/handler/region/ChannelWritableByteChannel.java @@ -34,13 +34,10 @@ import io.netty.channel.MessageEvent; /** * {@link WritableByteChannel} implementation which will take care to wrap the {@link ByteBuffer} to a {@link ChannelBuffer} and forward it to the next {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} on every {@link #write(ByteBuffer)} * operation. - * - - */ public class ChannelWritableByteChannel implements WritableByteChannel { - private boolean closed = false; + private boolean closed; private final ChannelHandlerContext context; private final ChannelFutureAggregator aggregator; private final SocketAddress remote; diff --git a/src/main/java/io/netty/handler/region/FileRegionEncoder.java b/handler/src/main/java/io/netty/handler/region/FileRegionEncoder.java similarity index 97% rename from src/main/java/io/netty/handler/region/FileRegionEncoder.java rename to handler/src/main/java/io/netty/handler/region/FileRegionEncoder.java index f361eace9f..2d73f645c0 100644 --- a/src/main/java/io/netty/handler/region/FileRegionEncoder.java +++ b/handler/src/main/java/io/netty/handler/region/FileRegionEncoder.java @@ -40,7 +40,7 @@ import io.netty.channel.MessageEvent; */ @ChannelHandler.Sharable -public class FileRegionEncoder implements ChannelDownstreamHandler{ +public class FileRegionEncoder implements ChannelDownstreamHandler { @Override public void handleDownstream( diff --git a/src/main/java/io/netty/container/microcontainer/package-info.java b/handler/src/main/java/io/netty/handler/region/package-info.java similarity index 81% rename from src/main/java/io/netty/container/microcontainer/package-info.java rename to handler/src/main/java/io/netty/handler/region/package-info.java index 485a26f619..2adc386e7f 100644 --- a/src/main/java/io/netty/container/microcontainer/package-info.java +++ b/handler/src/main/java/io/netty/handler/region/package-info.java @@ -15,8 +15,8 @@ */ /** - * JBoss Microcontainer integration. + * TODO: Replace this package and provide this functionality in the core. * - * @apiviz.exclude + * @apiviz.exclude \.channel\. */ -package io.netty.container.microcontainer; +package io.netty.handler.region; diff --git a/src/main/java/io/netty/handler/ssl/ImmediateExecutor.java b/handler/src/main/java/io/netty/handler/ssl/ImmediateExecutor.java similarity index 100% rename from src/main/java/io/netty/handler/ssl/ImmediateExecutor.java rename to handler/src/main/java/io/netty/handler/ssl/ImmediateExecutor.java diff --git a/src/main/java/io/netty/handler/ssl/SslBufferPool.java b/handler/src/main/java/io/netty/handler/ssl/SslBufferPool.java similarity index 100% rename from src/main/java/io/netty/handler/ssl/SslBufferPool.java rename to handler/src/main/java/io/netty/handler/ssl/SslBufferPool.java diff --git a/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java similarity index 99% rename from src/main/java/io/netty/handler/ssl/SslHandler.java rename to handler/src/main/java/io/netty/handler/ssl/SslHandler.java index 16e27b6832..059d524c0d 100644 --- a/src/main/java/io/netty/handler/ssl/SslHandler.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java @@ -194,7 +194,7 @@ public class SslHandler extends FrameDecoder private final Queue pendingUnencryptedWrites = new LinkedList(); private final Queue pendingEncryptedWrites = QueueFactory.createQueue(MessageEvent.class); private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock(); - private volatile boolean issueHandshake = false; + private volatile boolean issueHandshake; private static final ChannelFutureListener HANDSHAKE_LISTENER = new ChannelFutureListener() { @@ -414,7 +414,7 @@ public class SslHandler extends FrameDecoder /** * Enables or disables the automatic handshake once the {@link Channel} is connected. The value will only have affect if its set before the * {@link Channel} is connected. - */ + */ public void setIssueHandshake(boolean issueHandshake) { this.issueHandshake = issueHandshake; } diff --git a/src/main/java/io/netty/handler/ssl/package-info.java b/handler/src/main/java/io/netty/handler/ssl/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/ssl/package-info.java rename to handler/src/main/java/io/netty/handler/ssl/package-info.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedFile.java b/handler/src/main/java/io/netty/handler/stream/ChunkedFile.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedFile.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedFile.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedInput.java b/handler/src/main/java/io/netty/handler/stream/ChunkedInput.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedInput.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedInput.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedNioFile.java b/handler/src/main/java/io/netty/handler/stream/ChunkedNioFile.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedNioFile.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedNioFile.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedNioStream.java b/handler/src/main/java/io/netty/handler/stream/ChunkedNioStream.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedNioStream.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedNioStream.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedStream.java b/handler/src/main/java/io/netty/handler/stream/ChunkedStream.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedStream.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedStream.java diff --git a/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java b/handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java similarity index 100% rename from src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java rename to handler/src/main/java/io/netty/handler/stream/ChunkedWriteHandler.java diff --git a/src/main/java/io/netty/handler/stream/package-info.java b/handler/src/main/java/io/netty/handler/stream/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/stream/package-info.java rename to handler/src/main/java/io/netty/handler/stream/package-info.java diff --git a/src/main/java/io/netty/handler/timeout/DefaultIdleStateEvent.java b/handler/src/main/java/io/netty/handler/timeout/DefaultIdleStateEvent.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/DefaultIdleStateEvent.java rename to handler/src/main/java/io/netty/handler/timeout/DefaultIdleStateEvent.java diff --git a/src/main/java/io/netty/handler/timeout/IdleState.java b/handler/src/main/java/io/netty/handler/timeout/IdleState.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/IdleState.java rename to handler/src/main/java/io/netty/handler/timeout/IdleState.java diff --git a/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelHandler.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelHandler.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/IdleStateAwareChannelHandler.java rename to handler/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelHandler.java diff --git a/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelUpstreamHandler.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelUpstreamHandler.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/IdleStateAwareChannelUpstreamHandler.java rename to handler/src/main/java/io/netty/handler/timeout/IdleStateAwareChannelUpstreamHandler.java diff --git a/src/main/java/io/netty/handler/timeout/IdleStateEvent.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/IdleStateEvent.java rename to handler/src/main/java/io/netty/handler/timeout/IdleStateEvent.java diff --git a/src/main/java/io/netty/handler/timeout/IdleStateHandler.java b/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java similarity index 95% rename from src/main/java/io/netty/handler/timeout/IdleStateHandler.java rename to handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java index 28fed1bade..218194f6a3 100644 --- a/src/main/java/io/netty/handler/timeout/IdleStateHandler.java +++ b/handler/src/main/java/io/netty/handler/timeout/IdleStateHandler.java @@ -309,17 +309,23 @@ public class IdleStateHandler extends SimpleChannelUpstreamHandler private void destroy(ChannelHandlerContext ctx) { State state = (State) ctx.getAttachment(); - if (state.readerIdleTimeout != null) { - state.readerIdleTimeout.cancel(); - state.readerIdleTimeout = null; - } - if (state.writerIdleTimeout != null) { - state.writerIdleTimeout.cancel(); - state.writerIdleTimeout = null; - } - if (state.allIdleTimeout != null) { - state.allIdleTimeout.cancel(); - state.allIdleTimeout = null; + // Check if the state was set before, it may not if the destroy method was called before the + // channelOpen(...) method. + // + // See #143 + if (state != null) { + if (state.readerIdleTimeout != null) { + state.readerIdleTimeout.cancel(); + state.readerIdleTimeout = null; + } + if (state.writerIdleTimeout != null) { + state.writerIdleTimeout.cancel(); + state.writerIdleTimeout = null; + } + if (state.allIdleTimeout != null) { + state.allIdleTimeout.cancel(); + state.allIdleTimeout = null; + } } } diff --git a/src/main/java/io/netty/handler/timeout/ReadTimeoutException.java b/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutException.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/ReadTimeoutException.java rename to handler/src/main/java/io/netty/handler/timeout/ReadTimeoutException.java diff --git a/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java b/handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java rename to handler/src/main/java/io/netty/handler/timeout/ReadTimeoutHandler.java diff --git a/src/main/java/io/netty/handler/timeout/TimeoutException.java b/handler/src/main/java/io/netty/handler/timeout/TimeoutException.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/TimeoutException.java rename to handler/src/main/java/io/netty/handler/timeout/TimeoutException.java diff --git a/src/main/java/io/netty/handler/timeout/WriteTimeoutException.java b/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutException.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/WriteTimeoutException.java rename to handler/src/main/java/io/netty/handler/timeout/WriteTimeoutException.java diff --git a/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java b/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java similarity index 99% rename from src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java rename to handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java index f00a177024..b5af55d670 100644 --- a/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java +++ b/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java @@ -189,8 +189,6 @@ public class WriteTimeoutHandler extends SimpleChannelDownstreamHandler } } - /** - */ private static final class TimeoutCanceller implements ChannelFutureListener { private final Timeout timeout; diff --git a/src/main/java/io/netty/handler/timeout/package-info.java b/handler/src/main/java/io/netty/handler/timeout/package-info.java similarity index 100% rename from src/main/java/io/netty/handler/timeout/package-info.java rename to handler/src/main/java/io/netty/handler/timeout/package-info.java diff --git a/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java b/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java similarity index 69% rename from src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java rename to handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java index edd22e13f0..45219228b3 100644 --- a/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java +++ b/handler/src/main/java/io/netty/handler/traffic/AbstractTrafficShapingHandler.java @@ -18,6 +18,7 @@ package io.netty.handler.traffic; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import io.netty.buffer.ChannelBuffer; import io.netty.channel.Channel; import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelHandlerContext; @@ -27,9 +28,7 @@ import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelHandler; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; -import io.netty.util.DefaultObjectSizeEstimator; import io.netty.util.ExternalResourceReleasable; -import io.netty.util.ObjectSizeEstimator; import io.netty.util.internal.ExecutorUtil; /** @@ -41,10 +40,6 @@ import io.netty.util.internal.ExecutorUtil; * the method doAccounting of this handler.
*
* - * An {@link ObjectSizeEstimator} can be passed at construction to specify what - * is the size of the object to be read or write accordingly to the type of - * object. If not specified, it will used the {@link DefaultObjectSizeEstimator} implementation.

- * * If you want for any particular reasons to stop the monitoring (accounting) or to change * the read/write limit or the check interval, several methods allow that for you:
*
    @@ -75,27 +70,22 @@ public abstract class AbstractTrafficShapingHandler extends /** * Traffic Counter */ - protected TrafficCounter trafficCounter = null; - - /** - * ObjectSizeEstimator - */ - private ObjectSizeEstimator objectSizeEstimator = null; + protected TrafficCounter trafficCounter; /** * Executor to associated to any TrafficCounter */ - protected Executor executor = null; + protected Executor executor; /** * Limit in B/s to apply to write */ - private long writeLimit = 0; + private long writeLimit; /** * Limit in B/s to apply to read */ - private long readLimit = 0; + private long readLimit; /** * Delay between two performance snapshots @@ -109,17 +99,8 @@ public abstract class AbstractTrafficShapingHandler extends */ final AtomicBoolean release = new AtomicBoolean(false); - /** - * @param newObjectSizeEstimator - * @param newExecutor - * @param newWriteLimit - * @param newReadLimit - * @param newCheckInterval - */ - private void init(ObjectSizeEstimator newObjectSizeEstimator, - Executor newExecutor, long newWriteLimit, long newReadLimit, - long newCheckInterval) { - objectSizeEstimator = newObjectSizeEstimator; + private void init( + Executor newExecutor, long newWriteLimit, long newReadLimit, long newCheckInterval) { executor = newExecutor; writeLimit = newWriteLimit; readLimit = newReadLimit; @@ -136,8 +117,6 @@ public abstract class AbstractTrafficShapingHandler extends } /** - * Constructor using default {@link ObjectSizeEstimator} - * * @param executor * created for instance like Executors.newCachedThreadPool * @param writeLimit @@ -150,36 +129,10 @@ public abstract class AbstractTrafficShapingHandler extends */ public AbstractTrafficShapingHandler(Executor executor, long writeLimit, long readLimit, long checkInterval) { - init(new DefaultObjectSizeEstimator(), executor, writeLimit, readLimit, - checkInterval); + init(executor, writeLimit, readLimit, checkInterval); } /** - * Constructor using the specified ObjectSizeEstimator - * - * @param objectSizeEstimator - * the {@link ObjectSizeEstimator} that will be used to compute - * the size of the message - * @param executor - * created for instance like Executors.newCachedThreadPool - * @param writeLimit - * 0 or a limit in bytes/s - * @param readLimit - * 0 or a limit in bytes/s - * @param checkInterval - * The delay between two computations of performances for - * channels or 0 if no stats are to be computed - */ - public AbstractTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long writeLimit, long readLimit, long checkInterval) { - init(objectSizeEstimator, executor, writeLimit, readLimit, - checkInterval); - } - - /** - * Constructor using default {@link ObjectSizeEstimator} and using default Check Interval - * * @param executor * created for instance like Executors.newCachedThreadPool * @param writeLimit @@ -189,92 +142,11 @@ public abstract class AbstractTrafficShapingHandler extends */ public AbstractTrafficShapingHandler(Executor executor, long writeLimit, long readLimit) { - init(new DefaultObjectSizeEstimator(), executor, writeLimit, readLimit, - DEFAULT_CHECK_INTERVAL); - } - - /** - * Constructor using the specified ObjectSizeEstimator and using default Check Interval - * - * @param objectSizeEstimator - * the {@link ObjectSizeEstimator} that will be used to compute - * the size of the message - * @param executor - * created for instance like Executors.newCachedThreadPool - * @param writeLimit - * 0 or a limit in bytes/s - * @param readLimit - * 0 or a limit in bytes/s - */ - public AbstractTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long writeLimit, long readLimit) { - init(objectSizeEstimator, executor, writeLimit, readLimit, - DEFAULT_CHECK_INTERVAL); - } - - /** - * Constructor using default {@link ObjectSizeEstimator} and using NO LIMIT and default Check Interval - * - * @param executor - * created for instance like Executors.newCachedThreadPool - */ - public AbstractTrafficShapingHandler(Executor executor) { - init(new DefaultObjectSizeEstimator(), executor, 0, 0, - DEFAULT_CHECK_INTERVAL); - } - - /** - * Constructor using the specified ObjectSizeEstimator and using NO LIMIT and default Check Interval - * - * @param objectSizeEstimator - * the {@link ObjectSizeEstimator} that will be used to compute - * the size of the message - * @param executor - * created for instance like Executors.newCachedThreadPool - */ - public AbstractTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor) { - init(objectSizeEstimator, executor, 0, 0, DEFAULT_CHECK_INTERVAL); - } - - /** - * Constructor using default {@link ObjectSizeEstimator} and using NO LIMIT - * - * @param executor - * created for instance like Executors.newCachedThreadPool - * @param checkInterval - * The delay between two computations of performances for - * channels or 0 if no stats are to be computed - */ - public AbstractTrafficShapingHandler(Executor executor, long checkInterval) { - init(new DefaultObjectSizeEstimator(), executor, 0, 0, checkInterval); - } - - /** - * Constructor using the specified ObjectSizeEstimator and using NO LIMIT - * - * @param objectSizeEstimator - * the {@link ObjectSizeEstimator} that will be used to compute - * the size of the message - * @param executor - * created for instance like Executors.newCachedThreadPool - * @param checkInterval - * The delay between two computations of performances for - * channels or 0 if no stats are to be computed - */ - public AbstractTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long checkInterval) { - init(objectSizeEstimator, executor, 0, 0, checkInterval); + init(executor, writeLimit, readLimit, DEFAULT_CHECK_INTERVAL); } /** * Change the underlying limitations and check interval. - * - * @param newWriteLimit - * @param newReadLimit - * @param newCheckInterval */ public void configure(long newWriteLimit, long newReadLimit, long newCheckInterval) { @@ -284,22 +156,17 @@ public abstract class AbstractTrafficShapingHandler extends /** * Change the underlying limitations. - * - * @param newWriteLimit - * @param newReadLimit */ public void configure(long newWriteLimit, long newReadLimit) { writeLimit = newWriteLimit; readLimit = newReadLimit; if (trafficCounter != null) { - trafficCounter.resetAccounting(System.currentTimeMillis()+1); + trafficCounter.resetAccounting(System.currentTimeMillis() + 1); } } /** * Change the check interval. - * - * @param newCheckInterval */ public void configure(long newCheckInterval) { checkInterval = newCheckInterval; @@ -326,12 +193,12 @@ public abstract class AbstractTrafficShapingHandler extends /** * Associated ChannelHandlerContext */ - private ChannelHandlerContext ctx = null; + private ChannelHandlerContext ctx; /** * Time to wait before clearing the channel */ - private long timeToWait = 0; + private long timeToWait; /** * @param ctx @@ -388,7 +255,7 @@ public abstract class AbstractTrafficShapingHandler extends throws Exception { try { long curtime = System.currentTimeMillis(); - long size = objectSizeEstimator.estimateSize(arg1.getMessage()); + long size = ((ChannelBuffer) arg1.getMessage()).readableBytes(); if (trafficCounter != null) { trafficCounter.bytesRecvFlowControl(arg0, size); if (readLimit == 0) { @@ -448,7 +315,7 @@ public abstract class AbstractTrafficShapingHandler extends throws Exception { try { long curtime = System.currentTimeMillis(); - long size = objectSizeEstimator.estimateSize(arg1.getMessage()); + long size = ((ChannelBuffer) arg1.getMessage()).readableBytes(); if (trafficCounter != null) { trafficCounter.bytesWriteFlowControl(size); if (writeLimit == 0) { @@ -502,9 +369,6 @@ public abstract class AbstractTrafficShapingHandler extends return trafficCounter; } - /* (non-Javadoc) - * @see io.netty.util.ExternalResourceReleasable#releaseExternalResources() - */ @Override public void releaseExternalResources() { if (trafficCounter != null) { diff --git a/src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java b/handler/src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java similarity index 72% rename from src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java rename to handler/src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java index 197064e84d..0c8ca4b2ba 100644 --- a/src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java +++ b/handler/src/main/java/io/netty/handler/traffic/ChannelTrafficShapingHandler.java @@ -23,7 +23,6 @@ import io.netty.channel.ChannelStateEvent; import io.netty.handler.execution.ExecutionHandler; import io.netty.handler.execution.MemoryAwareThreadPoolExecutor; import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; -import io.netty.util.ObjectSizeEstimator; /** * This implementation of the {@link AbstractTrafficShapingHandler} is for channel @@ -34,7 +33,7 @@ import io.netty.util.ObjectSizeEstimator; *
  • Add in your pipeline a new ChannelTrafficShapingHandler, before a recommended {@link ExecutionHandler} (like * {@link OrderedMemoryAwareThreadPoolExecutor} or {@link MemoryAwareThreadPoolExecutor}).
    * ChannelTrafficShapingHandler myHandler = new ChannelTrafficShapingHandler(executor);
    - * executor could be created using Executors.newCachedThreadPool();
    + * executor could be created using Executors.newCachedThreadPool();
    * pipeline.addLast("CHANNEL_TRAFFIC_SHAPING", myHandler);

    * * Note that this handler has a Pipeline Coverage of "one" which means a new handler must be created @@ -81,67 +80,6 @@ public class ChannelTrafficShapingHandler extends AbstractTrafficShapingHandler super(executor, writeLimit, readLimit); } - /** - * @param executor - * @param checkInterval - */ - public ChannelTrafficShapingHandler(Executor executor, long checkInterval) { - super(executor, checkInterval); - } - - /** - * @param executor - */ - public ChannelTrafficShapingHandler(Executor executor) { - super(executor); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param writeLimit - * @param readLimit - * @param checkInterval - */ - public ChannelTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long writeLimit, long readLimit, long checkInterval) { - super(objectSizeEstimator, executor, writeLimit, readLimit, - checkInterval); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param writeLimit - * @param readLimit - */ - public ChannelTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long writeLimit, long readLimit) { - super(objectSizeEstimator, executor, writeLimit, readLimit); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param checkInterval - */ - public ChannelTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor, - long checkInterval) { - super(objectSizeEstimator, executor, checkInterval); - } - - /** - * @param objectSizeEstimator - * @param executor - */ - public ChannelTrafficShapingHandler( - ObjectSizeEstimator objectSizeEstimator, Executor executor) { - super(objectSizeEstimator, executor); - } - @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { diff --git a/src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java b/handler/src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java similarity index 66% rename from src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java rename to handler/src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java index de979de39c..73fc97df6d 100644 --- a/src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java +++ b/handler/src/main/java/io/netty/handler/traffic/GlobalTrafficShapingHandler.java @@ -21,7 +21,6 @@ import io.netty.channel.ChannelHandler.Sharable; import io.netty.handler.execution.ExecutionHandler; import io.netty.handler.execution.MemoryAwareThreadPoolExecutor; import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; -import io.netty.util.ObjectSizeEstimator; /** * This implementation of the {@link AbstractTrafficShapingHandler} is for global @@ -32,7 +31,7 @@ import io.netty.util.ObjectSizeEstimator; *
      *
    • Create your unique GlobalTrafficShapingHandler like:

      * GlobalTrafficShapingHandler myHandler = new GlobalTrafficShapingHandler(executor);

      - * executor could be created using Executors.newCachedThreadPool();
      + * executor could be created using Executors.newCachedThreadPool();
      * pipeline.addLast("GLOBAL_TRAFFIC_SHAPING", myHandler);

      * * Note that this handler has a Pipeline Coverage of "all" which means only one such handler must be created @@ -92,70 +91,4 @@ public class GlobalTrafficShapingHandler extends AbstractTrafficShapingHandler { super(executor, writeLimit, readLimit); createGlobalTrafficCounter(); } - - /** - * @param executor - * @param checkInterval - */ - public GlobalTrafficShapingHandler(Executor executor, long checkInterval) { - super(executor, checkInterval); - createGlobalTrafficCounter(); - } - - /** - * @param executor - */ - public GlobalTrafficShapingHandler(Executor executor) { - super(executor); - createGlobalTrafficCounter(); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param writeLimit - * @param readLimit - * @param checkInterval - */ - public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, - Executor executor, long writeLimit, long readLimit, - long checkInterval) { - super(objectSizeEstimator, executor, writeLimit, readLimit, - checkInterval); - createGlobalTrafficCounter(); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param writeLimit - * @param readLimit - */ - public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, - Executor executor, long writeLimit, long readLimit) { - super(objectSizeEstimator, executor, writeLimit, readLimit); - createGlobalTrafficCounter(); - } - - /** - * @param objectSizeEstimator - * @param executor - * @param checkInterval - */ - public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, - Executor executor, long checkInterval) { - super(objectSizeEstimator, executor, checkInterval); - createGlobalTrafficCounter(); - } - - /** - * @param objectSizeEstimator - * @param executor - */ - public GlobalTrafficShapingHandler(ObjectSizeEstimator objectSizeEstimator, - Executor executor) { - super(objectSizeEstimator, executor); - createGlobalTrafficCounter(); - } - } diff --git a/src/main/java/io/netty/handler/traffic/TrafficCounter.java b/handler/src/main/java/io/netty/handler/traffic/TrafficCounter.java similarity index 95% rename from src/main/java/io/netty/handler/traffic/TrafficCounter.java rename to handler/src/main/java/io/netty/handler/traffic/TrafficCounter.java index 1f56136734..4904d36840 100644 --- a/src/main/java/io/netty/handler/traffic/TrafficCounter.java +++ b/handler/src/main/java/io/netty/handler/traffic/TrafficCounter.java @@ -34,22 +34,22 @@ public class TrafficCounter { /** * Current written bytes */ - private final AtomicLong currentWrittenBytes = new AtomicLong(0); + private final AtomicLong currentWrittenBytes = new AtomicLong(); /** * Current read bytes */ - private final AtomicLong currentReadBytes = new AtomicLong(0); + private final AtomicLong currentReadBytes = new AtomicLong(); /** * Long life written bytes */ - private final AtomicLong cumulativeWrittenBytes = new AtomicLong(0); + private final AtomicLong cumulativeWrittenBytes = new AtomicLong(); /** * Long life read bytes */ - private final AtomicLong cumulativeReadBytes = new AtomicLong(0); + private final AtomicLong cumulativeReadBytes = new AtomicLong(); /** * Last Time where cumulative bytes where reset to zero @@ -59,27 +59,27 @@ public class TrafficCounter { /** * Last writing bandwidth */ - private long lastWriteThroughput = 0; + private long lastWriteThroughput; /** * Last reading bandwidth */ - private long lastReadThroughput = 0; + private long lastReadThroughput; /** * Last Time Check taken */ - private final AtomicLong lastTime = new AtomicLong(0); + private final AtomicLong lastTime = new AtomicLong(); /** * Last written bytes number during last check interval */ - private long lastWrittenBytes = 0; + private long lastWrittenBytes; /** * Last read bytes number during last check interval */ - private long lastReadBytes = 0; + private long lastReadBytes; /** * Delay between two captures @@ -97,22 +97,22 @@ public class TrafficCounter { /** * The associated TrafficShapingHandler */ - private AbstractTrafficShapingHandler trafficShapingHandler = null; + private AbstractTrafficShapingHandler trafficShapingHandler; /** * Default Executor */ - private Executor executor = null; + private Executor executor; /** * Is Monitor active */ - AtomicBoolean monitorActive = new AtomicBoolean(false); + AtomicBoolean monitorActive = new AtomicBoolean(); /** * Monitor */ - private TrafficMonitoring trafficMonitoring = null; + private TrafficMonitoring trafficMonitoring; /** * Class to implement monitoring at fix delay diff --git a/src/main/java/io/netty/handler/traffic/package-info.java b/handler/src/main/java/io/netty/handler/traffic/package-info.java similarity index 98% rename from src/main/java/io/netty/handler/traffic/package-info.java rename to handler/src/main/java/io/netty/handler/traffic/package-info.java index a5f6e0be00..2d2c2c2025 100644 --- a/src/main/java/io/netty/handler/traffic/package-info.java +++ b/handler/src/main/java/io/netty/handler/traffic/package-info.java @@ -34,7 +34,7 @@ * * The insertion in the pipeline of one of those handlers can be wherever you want, but * it must be placed before any {@link io.netty.handler.execution.MemoryAwareThreadPoolExecutor} - * in your pipeline.

    • + * in your pipeline
      .
      * It is really recommended to have such a {@link io.netty.handler.execution.MemoryAwareThreadPoolExecutor} * (either non ordered or {@link io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor} * ) in your pipeline @@ -74,7 +74,7 @@ * *

      So in your application you will create your own TrafficShapingHandler and set the values to fit your needs.

      * XXXXXTrafficShapingHandler myHandler = new XXXXXTrafficShapingHandler(executor);

      - * where executor could be created using Executors.newCachedThreadPool(); and XXXXX could be either + * where executor could be created using Executors.newCachedThreadPool(); and XXXXX could be either * Global or Channel
      * pipeline.addLast("XXXXX_TRAFFIC_SHAPING", myHandler);
      * ...
      diff --git a/src/test/java/io/netty/handler/ipfilter/IpFilterRuleTest.java b/handler/src/test/java/io/netty/handler/ipfilter/IpFilterRuleTest.java similarity index 100% rename from src/test/java/io/netty/handler/ipfilter/IpFilterRuleTest.java rename to handler/src/test/java/io/netty/handler/ipfilter/IpFilterRuleTest.java diff --git a/src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java b/handler/src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java similarity index 99% rename from src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java rename to handler/src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java index a8538ad3ee..1b8111fa9c 100644 --- a/src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java +++ b/handler/src/test/java/io/netty/handler/ssl/ImmediateExecutorTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class ImmediateExecutorTest { @Test diff --git a/pom.xml b/pom.xml index 70c128d1cc..6ac479d717 100644 --- a/pom.xml +++ b/pom.xml @@ -24,20 +24,16 @@ io.netty - netty - bundle + netty-parent + pom 4.0.0.Alpha1-SNAPSHOT - The Netty Project - http://io.netty/ + Netty + http://netty.io/ - The Netty project is an effort to provide an asynchronous event-driven - network application framework and tools for rapid development of - maintainable high performance and high scalability protocol servers and - clients. In other words, Netty is a NIO client server framework which - enables quick and easy development of network applications such as protocol - servers and clients. It greatly simplifies and streamlines network - programming such as TCP and UDP socket server. + Netty is an asynchronous event-driven network application framework for + rapid development of maintainable high performance protocol servers and + clients. @@ -70,110 +66,105 @@ + + common + buffer + codec + codec-http + transport + transport-http + transport-rxtx + transport-sctp + handler + example + all + testsuite + + + + + + com.google.protobuf + protobuf-java + 2.4.1 + + + + org.rxtx + rxtx + 2.1.7 + + + + javax.servlet + servlet-api + 2.5 + + + + org.apache.felix + org.osgi.core + 1.4.0 + + + org.apache.felix + org.osgi.compendium + 1.4.0 + + + org.apache.felix + javax.servlet + + + org.apache.felix + org.osgi.foundation + + + + + + org.slf4j + slf4j-api + 1.6.4 + + + commons-logging + commons-logging + 1.1.1 + + + org.jboss.logging + jboss-logging-spi + 2.1.2.GA + + + log4j + log4j + 1.2.16 + + + mail + javax.mail + + + jms + javax.jms + + + jmxtools + com.sun.jdmk + + + jmxri + com.sun.jmx + + + true + + + + - - - com.google.protobuf - protobuf-java - 2.4.1 - compile - true - - - - - - org.rxtx - rxtx - 2.1.7 - compile - true - - - - - - javax.servlet - servlet-api - 2.5 - compile - true - - - - - org.apache.felix - org.osgi.core - 1.4.0 - compile - true - - - org.apache.felix - org.osgi.compendium - 1.4.0 - compile - true - - - org.apache.felix - javax.servlet - - - org.apache.felix - org.osgi.foundation - - - - - - - org.slf4j - slf4j-api - 1.6.4 - compile - true - - - commons-logging - commons-logging - 1.1.1 - compile - true - - - org.jboss.logging - jboss-logging-spi - 2.1.2.GA - compile - true - - - log4j - log4j - 1.2.16 - compile - - - mail - javax.mail - - - jms - javax.jms - - - jmxtools - com.sun.jdmk - - - jmxri - com.sun.jmx - - - true - - junit @@ -207,53 +198,7 @@ - - 1.6 - 2.2.1 - false - - - - - ${basedir}/src/main/resources - - - ${basedir}/target/license - - - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.maven.plugins - maven-antrun-plugin - [1.7,) - - run - - - - - - - - - - - - - maven-enforcer-plugin @@ -293,325 +238,64 @@ - maven-resources-plugin - 2.5 - - UTF-8 - + maven-checkstyle-plugin + 2.8 - copy-legal-info + check-style + + check + validate - - copy-resources - - ${basedir}/target/license/META-INF - - - ${basedir} - false - - LICENSE.txt - NOTICE.txt - license/*.txt - - - - - - - - - maven-surefire-plugin - 2.10 - - once - - **/Abstract* - **/TestUtil* - - - - - org.apache.felix - maven-bundle-plugin - 2.3.4 - true - - - ${project.groupId} - ${project.url} - - ${project.groupId}.container.osgi.NettyBundleActivator - - - !${project.groupId}.example.*, - !${project.groupId}.util.internal.*, - ${project.groupId}.*;version=${project.version} - - - ${project.groupId}.example.*, - ${project.groupId}.util.internal.*, - - - *;resolution:=optional - - registered - registered - ${project.groupId}.util.Version - - - - - maven-source-plugin - 2.1.2 - - - attach-source - package - - jar - - - true - - - - - - maven-antrun-plugin - 1.7 - - - write-version - validate - - run - - - - - - - - - - - - - - - - - - - Build number: ${buildNumber} - - - - - - - - remove-examples - package - - run - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + true + true + true + true + io/netty/checkstyle.xml - org.apache.ant - ant - 1.8.2 - - - org.apache.ant - ant-launcher - 1.8.2 - - - ant-contrib - ant-contrib - 1.0b3 - - - ant - ant - - + ${project.groupId} + netty-build + 6 - - maven-javadoc-plugin - 2.8 - - - attach-javadoc - package - - jar - - - - - org.jboss.apiviz.APIviz - ${basedir}/lib/apiviz-1.3.1.GA.jar - true - ${basedir}/src/javadoc - true - true - ${project.build.directory}/api - UTF-8 - UTF-8 - true - false - false - true - ${basedir}/src/javadoc/overview.html - ${project.name} API Reference (${project.version}) - ${project.name} API Reference (${project.version}) - - -link http://java.sun.com/javase/6/docs/api/ - -link http://code.google.com/apis/protocolbuffers/docs/reference/java/ - -link http://java.sun.com/products/servlet/2.5/docs/servlet-2_5-mr2/ - -link http://www.osgi.org/javadoc/r4v41/ - -link http://www.slf4j.org/apidocs/ - -link http://commons.apache.org/logging/commons-logging-1.1.1/apidocs/ - -link http://logging.apache.org/log4j/1.2/apidocs/ - - -group "Low-level data representation" ${project.groupId}.buffer* - -group "Central interface for all I/O operations" ${project.groupId}.channel* - -group "Client & Server bootstrapping utilities" ${project.groupId}.bootstrap* - -group "Reusable I/O event interceptors" ${project.groupId}.handler* - -group "Miscellaneous" ${project.groupId}.logging*:${project.groupId}.util* - - -sourceclasspath ${project.build.outputDirectory} - -nopackagediagram - - UTF-8 - en_US - ${project.groupId}.example*:${project.groupId}.container*:${project.groupId}.util.internal* - - - - maven-jxr-plugin - 2.2 - - - generate-xref - package - - jxr - - - - - UTF-8 - UTF-8 - true - ${project.build.directory}/xref - ${project.build.directory}/api - ${project.name} Source Xref (${project.version}) - ${project.name} Source Xref (${project.version}) - - - - maven-assembly-plugin - 2.2.1 - - - generate-distribution - package - - single - - - - - - ${basedir}/src/assembly/default.xml - - ${attach-distribution} - true - gnu - - - - maven-gpg-plugin - 1.4 - - - sign-artifacts - verify - - sign - - - - - - maven-release-plugin - 2.2.1 - - - false - - -Prelease - - - - maven-eclipse-plugin - 2.8 - - true - true - - + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + [1.0,) + + check + + + + + + + + + + + + diff --git a/src/assembly/default.xml b/src/assembly/default.xml deleted file mode 100644 index bc23c01229..0000000000 --- a/src/assembly/default.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - dist - - tar.bz2 - - false - - - - - **/README* - **/LICENSE* - **/NOTICE* - **/COPYRIGHT* - **/*.txt - **/*.xml - **/license/** - **/src/** - - - **/target/** - **/.*/** - - - - - - target - jar - - ${project.build.finalName}*.jar - - - ${project.build.finalName}*-javadoc.jar - - - - - - target/api - doc/api - - **/** - - - - - - target/xref - doc/xref - - **/** - - - - - diff --git a/src/javadoc/overview.html b/src/javadoc/overview.html deleted file mode 100644 index 2400b25973..0000000000 --- a/src/javadoc/overview.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - The Netty Project API Reference - - -
      -

      The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP/IP socket server.

      - - diff --git a/src/main/java/io/netty/channel/StaticChannelPipeline.java b/src/main/java/io/netty/channel/StaticChannelPipeline.java deleted file mode 100644 index 98d377a177..0000000000 --- a/src/main/java/io/netty/channel/StaticChannelPipeline.java +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.internal.ConversionUtil; - -/** - * A {@link ChannelPipeline} that might perform better at the cost of - * disabled dynamic insertion and removal of {@link ChannelHandler}s. - * An attempt to insert, remove, or replace a handler in this pipeline will - * trigger an {@link UnsupportedOperationException}. - */ -public class StaticChannelPipeline implements ChannelPipeline { - - // FIXME Code duplication with DefaultChannelPipeline - static final InternalLogger logger = InternalLoggerFactory.getInstance(StaticChannelPipeline.class); - - private volatile Channel channel; - private volatile ChannelSink sink; - private final StaticChannelHandlerContext[] contexts; - private final int lastIndex; - private final Map name2ctx = - new HashMap(4); - - /** - * Creates a new pipeline from the specified handlers. - * The names of the specified handlers are generated automatically; - * the first handler's name is {@code "0"}, the second handler's name is - * {@code "1"}, the third handler's name is {@code "2"}, and so on. - */ - public StaticChannelPipeline(ChannelHandler... handlers) { - if (handlers == null) { - throw new NullPointerException("handlers"); - } - if (handlers.length == 0) { - throw new IllegalArgumentException("no handlers specified"); - } - - // Get the number of first non-null handlers. - StaticChannelHandlerContext[] contexts = - new StaticChannelHandlerContext[handlers.length]; - int nContexts; - for (nContexts = 0; nContexts < contexts.length; nContexts ++) { - ChannelHandler h = handlers[nContexts]; - if (h == null) { - break; - } - } - - if (nContexts == contexts.length) { - this.contexts = contexts; - lastIndex = contexts.length - 1; - } else { - this.contexts = contexts = - new StaticChannelHandlerContext[nContexts]; - lastIndex = nContexts - 1; - } - - // Initialize the first non-null handlers only. - for (int i = 0; i < nContexts; i ++) { - ChannelHandler h = handlers[i]; - String name = ConversionUtil.toString(i); - StaticChannelHandlerContext ctx = - new StaticChannelHandlerContext(i, name, h); - contexts[i] = ctx; - name2ctx.put(name, ctx); - } - - for (ChannelHandlerContext ctx: contexts) { - callBeforeAdd(ctx); - callAfterAdd(ctx); - } - } - - @Override - public Channel getChannel() { - return channel; - } - - @Override - public ChannelSink getSink() { - ChannelSink sink = this.sink; - if (sink == null) { - return DefaultChannelPipeline.discardingSink; - } - return sink; - } - - @Override - public void attach(Channel channel, ChannelSink sink) { - if (channel == null) { - throw new NullPointerException("channel"); - } - if (sink == null) { - throw new NullPointerException("sink"); - } - if (this.channel != null || this.sink != null) { - throw new IllegalStateException("attached already"); - } - this.channel = channel; - this.sink = sink; - } - - @Override - public boolean isAttached() { - return sink != null; - } - - @Override - public void addFirst(String name, ChannelHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public void addLast(String name, ChannelHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public void addBefore(String baseName, String name, ChannelHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public void addAfter(String baseName, String name, ChannelHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public void remove(ChannelHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public ChannelHandler remove(String name) { - throw new UnsupportedOperationException(); - } - - @Override - public T remove(Class handlerType) { - throw new UnsupportedOperationException(); - } - - @Override - public ChannelHandler removeFirst() { - throw new UnsupportedOperationException(); - } - - @Override - public ChannelHandler removeLast() { - throw new UnsupportedOperationException(); - } - - @Override - public void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler) { - throw new UnsupportedOperationException(); - } - - @Override - public ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler) { - throw new UnsupportedOperationException(); - } - - @Override - public T replace( - Class oldHandlerType, String newName, ChannelHandler newHandler) { - throw new UnsupportedOperationException(); - } - - private void callBeforeAdd(ChannelHandlerContext ctx) { - if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { - return; - } - - LifeCycleAwareChannelHandler h = - (LifeCycleAwareChannelHandler) ctx.getHandler(); - - try { - h.beforeAdd(ctx); - } catch (Throwable t) { - throw new ChannelHandlerLifeCycleException( - h.getClass().getName() + - ".beforeAdd() has thrown an exception; not adding.", t); - } - } - - private void callAfterAdd(ChannelHandlerContext ctx) { - if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { - return; - } - - LifeCycleAwareChannelHandler h = - (LifeCycleAwareChannelHandler) ctx.getHandler(); - - try { - h.afterAdd(ctx); - } catch (Throwable t) { - boolean removed = false; - try { - callBeforeRemove(ctx); - callAfterRemove(ctx); - removed = true; - } catch (Throwable t2) { - logger.warn("Failed to remove a handler: " + ctx.getName(), t2); - } - - if (removed) { - throw new ChannelHandlerLifeCycleException( - h.getClass().getName() + - ".afterAdd() has thrown an exception; removed.", t); - } else { - throw new ChannelHandlerLifeCycleException( - h.getClass().getName() + - ".afterAdd() has thrown an exception; also failed to remove.", t); - } - } - } - - private void callBeforeRemove(ChannelHandlerContext ctx) { - if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { - return; - } - - LifeCycleAwareChannelHandler h = - (LifeCycleAwareChannelHandler) ctx.getHandler(); - - try { - h.beforeRemove(ctx); - } catch (Throwable t) { - throw new ChannelHandlerLifeCycleException( - h.getClass().getName() + - ".beforeRemove() has thrown an exception; not removing.", t); - } - } - - private void callAfterRemove(ChannelHandlerContext ctx) { - if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) { - return; - } - - LifeCycleAwareChannelHandler h = - (LifeCycleAwareChannelHandler) ctx.getHandler(); - - try { - h.afterRemove(ctx); - } catch (Throwable t) { - throw new ChannelHandlerLifeCycleException( - h.getClass().getName() + - ".afterRemove() has thrown an exception.", t); - } - } - - @Override - public ChannelHandler getFirst() { - return contexts[0].getHandler(); - } - - @Override - public ChannelHandler getLast() { - return contexts[contexts.length - 1].getHandler(); - } - - @Override - public ChannelHandler get(String name) { - StaticChannelHandlerContext ctx = name2ctx.get(name); - if (ctx == null) { - return null; - } else { - return ctx.getHandler(); - } - } - - @Override - @SuppressWarnings("unchecked") - public T get(Class handlerType) { - ChannelHandlerContext ctx = getContext(handlerType); - if (ctx == null) { - return null; - } else { - return (T) ctx.getHandler(); - } - } - - @Override - public ChannelHandlerContext getContext(String name) { - if (name == null) { - throw new NullPointerException("name"); - } - return name2ctx.get(name); - } - - @Override - public ChannelHandlerContext getContext(ChannelHandler handler) { - if (handler == null) { - throw new NullPointerException("handler"); - } - for (StaticChannelHandlerContext ctx: contexts) { - if (ctx.getHandler() == handler) { - return ctx; - } - } - return null; - } - - @Override - public ChannelHandlerContext getContext(Class handlerType) { - if (handlerType == null) { - throw new NullPointerException("handlerType"); - } - for (StaticChannelHandlerContext ctx: contexts) { - if (handlerType.isAssignableFrom(ctx.getHandler().getClass())) { - return ctx; - } - } - return null; - } - - @Override - public List getNames() { - List list = new ArrayList(); - for (StaticChannelHandlerContext ctx: contexts) { - list.add(ctx.getName()); - } - return list; - } - - @Override - public Map toMap() { - Map map = new LinkedHashMap(); - for (StaticChannelHandlerContext ctx: contexts) { - map.put(ctx.getName(), ctx.getHandler()); - } - return map; - } - - /** - * Returns the {@link String} representation of this pipeline. - */ - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append(getClass().getSimpleName()); - buf.append('{'); - - for (StaticChannelHandlerContext ctx: contexts) { - buf.append('('); - buf.append(ctx.getName()); - buf.append(" = "); - buf.append(ctx.getHandler().getClass().getName()); - buf.append(')'); - buf.append(", "); - } - buf.replace(buf.length() - 2, buf.length(), "}"); - return buf.toString(); - } - - @Override - public void sendUpstream(ChannelEvent e) { - StaticChannelHandlerContext head = getActualUpstreamContext(0); - if (head == null) { - logger.warn( - "The pipeline contains no upstream handlers; discarding: " + e); - return; - } - - sendUpstream(head, e); - } - - void sendUpstream(StaticChannelHandlerContext ctx, ChannelEvent e) { - try { - ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e); - } catch (Throwable t) { - notifyHandlerException(e, t); - } - } - - @Override - public void sendDownstream(ChannelEvent e) { - StaticChannelHandlerContext tail = getActualDownstreamContext(lastIndex); - if (tail == null) { - try { - getSink().eventSunk(this, e); - return; - } catch (Throwable t) { - notifyHandlerException(e, t); - return; - } - } - - sendDownstream(tail, e); - } - - void sendDownstream(StaticChannelHandlerContext ctx, ChannelEvent e) { - if (e instanceof UpstreamMessageEvent) { - throw new IllegalArgumentException("cannot send an upstream event to downstream"); - } - - try { - ((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e); - } catch (Throwable t) { - // Unlike an upstream event, a downstream event usually has an - // incomplete future which is supposed to be updated by ChannelSink. - // However, if an exception is raised before the event reaches at - // ChannelSink, the future is not going to be updated, so we update - // here. - e.getFuture().setFailure(t); - notifyHandlerException(e, t); - } - } - - StaticChannelHandlerContext getActualUpstreamContext(int index) { - for (int i = index; i < contexts.length; i ++) { - StaticChannelHandlerContext ctx = contexts[i]; - if (ctx.canHandleUpstream()) { - return ctx; - } - } - return null; - } - - StaticChannelHandlerContext getActualDownstreamContext(int index) { - for (int i = index; i >= 0; i --) { - StaticChannelHandlerContext ctx = contexts[i]; - if (ctx.canHandleDownstream()) { - return ctx; - } - } - return null; - } - - protected void notifyHandlerException(ChannelEvent e, Throwable t) { - if (e instanceof ExceptionEvent) { - logger.warn( - "An exception was thrown by a user handler " + - "while handling an exception event (" + e + ")", t); - return; - } - - ChannelPipelineException pe; - if (t instanceof ChannelPipelineException) { - pe = (ChannelPipelineException) t; - } else { - pe = new ChannelPipelineException(t); - } - - try { - sink.exceptionCaught(this, e, pe); - } catch (Exception e1) { - logger.warn("An exception was thrown by an exception handler.", e1); - } - } - - private final class StaticChannelHandlerContext implements ChannelHandlerContext { - private final int index; - private final String name; - private final ChannelHandler handler; - private final boolean canHandleUpstream; - private final boolean canHandleDownstream; - private volatile Object attachment; - - StaticChannelHandlerContext( - int index, String name, ChannelHandler handler) { - - if (name == null) { - throw new NullPointerException("name"); - } - if (handler == null) { - throw new NullPointerException("handler"); - } - canHandleUpstream = handler instanceof ChannelUpstreamHandler; - canHandleDownstream = handler instanceof ChannelDownstreamHandler; - - - if (!canHandleUpstream && !canHandleDownstream) { - throw new IllegalArgumentException( - "handler must be either " + - ChannelUpstreamHandler.class.getName() + " or " + - ChannelDownstreamHandler.class.getName() + '.'); - } - - this.index = index; - this.name = name; - this.handler = handler; - } - - @Override - public Channel getChannel() { - return getPipeline().getChannel(); - } - - @Override - public ChannelPipeline getPipeline() { - return StaticChannelPipeline.this; - } - - @Override - public boolean canHandleDownstream() { - return canHandleDownstream; - } - - @Override - public boolean canHandleUpstream() { - return canHandleUpstream; - } - - @Override - public ChannelHandler getHandler() { - return handler; - } - - @Override - public String getName() { - return name; - } - - @Override - public Object getAttachment() { - return attachment; - } - - @Override - public void setAttachment(Object attachment) { - this.attachment = attachment; - } - - @Override - public void sendDownstream(ChannelEvent e) { - StaticChannelHandlerContext prev = getActualDownstreamContext(index - 1); - if (prev == null) { - try { - getSink().eventSunk(StaticChannelPipeline.this, e); - } catch (Throwable t) { - notifyHandlerException(e, t); - } - } else { - StaticChannelPipeline.this.sendDownstream(prev, e); - } - } - - @Override - public void sendUpstream(ChannelEvent e) { - StaticChannelHandlerContext next = getActualUpstreamContext(index + 1); - if (next != null) { - StaticChannelPipeline.this.sendUpstream(next, e); - } - } - } -} diff --git a/src/main/java/io/netty/container/osgi/NettyBundleActivator.java b/src/main/java/io/netty/container/osgi/NettyBundleActivator.java deleted file mode 100644 index 8b2f66fd3a..0000000000 --- a/src/main/java/io/netty/container/osgi/NettyBundleActivator.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.container.osgi; - -import io.netty.logging.InternalLoggerFactory; -import io.netty.logging.OsgiLoggerFactory; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -/** - * An OSGi {@link BundleActivator} that configures logging. - */ -public class NettyBundleActivator implements BundleActivator { - - private OsgiLoggerFactory loggerFactory; - - @Override - public void start(BundleContext ctx) throws Exception { - // Switch the internal logger to the OSGi LogService. - loggerFactory = new OsgiLoggerFactory(ctx); - InternalLoggerFactory.setDefaultFactory(loggerFactory); - } - - @Override - public void stop(BundleContext ctx) throws Exception { - if (loggerFactory != null) { - InternalLoggerFactory.setDefaultFactory(loggerFactory.getFallback()); - loggerFactory.destroy(); - loggerFactory = null; - } - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerHandler.java b/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerHandler.java deleted file mode 100644 index 204679d734..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/autobahn/WebSocketServerHandler.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.autobahn; - -import static io.netty.handler.codec.http.HttpHeaders.*; -import static io.netty.handler.codec.http.HttpMethod.*; -import static io.netty.handler.codec.http.HttpResponseStatus.*; -import static io.netty.handler.codec.http.HttpVersion.*; - -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ExceptionEvent; -import io.netty.channel.MessageEvent; -import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.handler.codec.http.DefaultHttpResponse; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.CharsetUtil; - -/** - * Handles handshakes and messages - */ -public class WebSocketServerHandler extends SimpleChannelUpstreamHandler { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class); - - private WebSocketServerHandshaker handshaker = null; - - @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - Object msg = e.getMessage(); - if (msg instanceof HttpRequest) { - handleHttpRequest(ctx, (HttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); - } - } - - private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { - // Allow only GET methods. - if (req.getMethod() != GET) { - sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); - return; - } - - // Handshake - WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( - this.getWebSocketLocation(req), null, false); - this.handshaker = wsFactory.newHandshaker(req); - if (this.handshaker == null) { - wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); - } else { - this.handshaker.performOpeningHandshake(ctx.getChannel(), req); - } - } - - private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { - logger.debug(String - .format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName())); - - if (frame instanceof CloseWebSocketFrame) { - this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame); - } else if (frame instanceof PingWebSocketFrame) { - ctx.getChannel().write( - new PongWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); - } else if (frame instanceof TextWebSocketFrame) { - //String text = ((TextWebSocketFrame) frame).getText(); - ctx.getChannel().write(new TextWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); - } else if (frame instanceof BinaryWebSocketFrame) { - ctx.getChannel().write( - new BinaryWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); - } else if (frame instanceof ContinuationWebSocketFrame) { - ctx.getChannel().write( - new ContinuationWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData())); - } else if (frame instanceof PongWebSocketFrame) { - // Ignore - } else { - throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() - .getName())); - } - } - - private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { - // Generate an error page if response status code is not OK (200). - if (res.getStatus().getCode() != 200) { - res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); - setContentLength(res, res.getContent().readableBytes()); - } - - // Send the response and close the connection if necessary. - ChannelFuture f = ctx.getChannel().write(res); - if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { - f.addListener(ChannelFutureListener.CLOSE); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - e.getCause().printStackTrace(); - e.getChannel().close(); - } - - private String getWebSocketLocation(HttpRequest req) { - return "ws://" + req.getHeader(HttpHeaders.Names.HOST); - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/client/App.java b/src/main/java/io/netty/example/http/websocketx/client/App.java deleted file mode 100644 index 2928923e6e..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/client/App.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.example.http.websocketx.client; - -import java.net.URI; -import java.util.ArrayList; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.netty.buffer.ChannelBuffers; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketSpecificationVersion; - -/** - * A HTTP client demo app - */ -public class App { - - public static void main(String[] args) throws Exception { - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINE); - Logger.getLogger("").addHandler(ch); - Logger.getLogger("").setLevel(Level.FINE); - - runClient(); - System.exit(0); - } - - /** - * Send and receive some messages using a web socket client - * - * @throws Exception - */ - public static void runClient() throws Exception { - - MyCallbackHandler callbackHandler = new MyCallbackHandler(); - WebSocketClientFactory factory = new WebSocketClientFactory(); - - // Connect with spec version 17. You can change it to V10 or V00. - // If you change it to V00, ping is not supported and remember to change HttpResponseDecoder to - // WebSocketHttpResponseDecoder in the pipeline. - WebSocketClient client = factory.newClient(new URI("ws://localhost:8080/websocket"), - WebSocketSpecificationVersion.V17, callbackHandler); - - // Connect - System.out.println("WebSocket Client connecting"); - client.connect().awaitUninterruptibly(); - Thread.sleep(200); - - // Send 10 messages and wait for responses - System.out.println("WebSocket Client sending message"); - for (int i = 0; i < 10; i++) { - client.send(new TextWebSocketFrame("Message #" + i)); - } - Thread.sleep(1000); - - // Ping - only supported for V10 and up. - System.out.println("WebSocket Client sending ping"); - client.send(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 }))); - Thread.sleep(1000); - - // Close - System.out.println("WebSocket Client sending close"); - client.send(new CloseWebSocketFrame()); - Thread.sleep(1000); - - // Disconnect - client.disconnect(); - } - - /** - * Our web socket callback handler for this app - */ - public static class MyCallbackHandler implements WebSocketCallback { - public boolean connected = false; - public ArrayList messagesReceived = new ArrayList(); - - public MyCallbackHandler() { - } - - @Override - public void onConnect(WebSocketClient client) { - System.out.println("WebSocket Client connected!"); - connected = true; - } - - @Override - public void onDisconnect(WebSocketClient client) { - System.out.println("WebSocket Client disconnected!"); - connected = false; - } - - @Override - public void onMessage(WebSocketClient client, WebSocketFrame frame) { - if (frame instanceof TextWebSocketFrame) { - TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; - System.out.println("WebSocket Client received message:" + textFrame.getText()); - messagesReceived.add(textFrame.getText()); - } else if (frame instanceof PongWebSocketFrame) { - System.out.println("WebSocket Client received pong"); - } else if (frame instanceof CloseWebSocketFrame) { - System.out.println("WebSocket Client received closing"); - } - } - - @Override - public void onError(Throwable t) { - System.out.println("WebSocket Client error " + t.toString()); - } - - } - -} diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketCallback.java b/src/main/java/io/netty/example/http/websocketx/client/WebSocketCallback.java deleted file mode 100644 index 38de78d572..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketCallback.java +++ /dev/null @@ -1,68 +0,0 @@ -//The MIT License -// -//Copyright (c) 2009 Carl Bystršm -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. - -package io.netty.example.http.websocketx.client; - -import io.netty.handler.codec.http.websocketx.WebSocketFrame; - - -/** - * Copied from https://github.com/cgbystrom/netty-tools - * - * Callbacks for the {@link WebSocketClient}. Implement and get notified when events happen. - */ -public interface WebSocketCallback { - - /** - * Called when the client is connected to the server - * - * @param client - * Current client used to connect - */ - void onConnect(WebSocketClient client); - - /** - * Called when the client got disconnected from the server. - * - * @param client - * Current client that was disconnected - */ - void onDisconnect(WebSocketClient client); - - /** - * Called when a message arrives from the server. - * - * @param client - * Current client connected - * @param frame - * Data received from server - */ - void onMessage(WebSocketClient client, WebSocketFrame frame); - - /** - * Called when an unhandled errors occurs. - * - * @param t - * The causing error - */ - void onError(Throwable t); -} diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java b/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java deleted file mode 100644 index 24064bb56b..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClient.java +++ /dev/null @@ -1,54 +0,0 @@ -//The MIT License -// -//Copyright (c) 2009 Carl Bystršm -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -package io.netty.example.http.websocketx.client; - -import io.netty.channel.ChannelFuture; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; - -/** - * Copied from https://github.com/cgbystrom/netty-tools - */ -public interface WebSocketClient { - - /** - * Connect to server Host and port is setup by the factory. - * - * @return Connect future. Fires when connected. - */ - ChannelFuture connect(); - - /** - * Disconnect from the server - * - * @return Disconnect future. Fires when disconnected. - */ - ChannelFuture disconnect(); - - /** - * Send data to server - * - * @param frame - * Data for sending - * @return Write future. Will fire when the data is sent. - */ - ChannelFuture send(WebSocketFrame frame); -} diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientFactory.java b/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientFactory.java deleted file mode 100644 index 47e758e0ee..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketClientFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -//The MIT License -// -//Copyright (c) 2009 Carl Bystršm -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. - -package io.netty.example.http.websocketx.client; - -import io.netty.bootstrap.ClientBootstrap; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelPipelineFactory; -import io.netty.channel.Channels; -import io.netty.channel.socket.nio.NioClientSocketChannelFactory; -import io.netty.handler.codec.http.HttpRequestEncoder; -import io.netty.handler.codec.http.HttpResponseDecoder; -import io.netty.handler.codec.http.websocketx.WebSocketSpecificationVersion; - -import java.net.URI; -import java.util.concurrent.Executors; - -/** - * Copied from https://github.com/cgbystrom/netty-tools - * - * A factory for creating WebSocket clients. The entry point for creating and connecting a client. Can and should be - * used to create multiple instances. - */ -public class WebSocketClientFactory { - - private final NioClientSocketChannelFactory socketChannelFactory = new NioClientSocketChannelFactory( - Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); - - /** - * Create a new WebSocket client. - * - * @param url - * URL to connect to. - * @param version - * Web Socket version to support - * @param callback - * Callback interface to receive events - * @return A WebSocket client. Call {@link WebSocketClient#connect()} to connect. - */ - public WebSocketClient newClient(final URI url, - final WebSocketSpecificationVersion version, - final WebSocketCallback callback) { - ClientBootstrap bootstrap = new ClientBootstrap(socketChannelFactory); - - String protocol = url.getScheme(); - if (!protocol.equals("ws") && !protocol.equals("wss")) { - throw new IllegalArgumentException("Unsupported protocol: " + protocol); - } - - final WebSocketClientHandler clientHandler = new WebSocketClientHandler(bootstrap, url, version, callback); - - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - @Override - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - - // If you wish to support HyBi V00, you need to use WebSocketHttpResponseDecoder instead for - // HttpResponseDecoder. - pipeline.addLast("decoder", new HttpResponseDecoder()); - - pipeline.addLast("encoder", new HttpRequestEncoder()); - pipeline.addLast("ws-handler", clientHandler); - return pipeline; - } - }); - - return clientHandler; - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/client/WebSocketException.java b/src/main/java/io/netty/example/http/websocketx/client/WebSocketException.java deleted file mode 100644 index ed227a7925..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/client/WebSocketException.java +++ /dev/null @@ -1,44 +0,0 @@ -//The MIT License -// -//Copyright (c) 2009 Carl Bystršm -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -package io.netty.example.http.websocketx.client; - -import java.io.IOException; - -/** - * Copied from https://github.com/cgbystrom/netty-tools - * - * A WebSocket related exception - */ -public class WebSocketException extends IOException { - - /** - */ - private static final long serialVersionUID = 1L; - - public WebSocketException(String s) { - super(s); - } - - public WebSocketException(String s, Throwable throwable) { - super(s, throwable); - } -} \ No newline at end of file diff --git a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java b/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java deleted file mode 100644 index 702e15b8e6..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerHandler.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.server; - -import static io.netty.handler.codec.http.HttpHeaders.*; -import static io.netty.handler.codec.http.HttpHeaders.Names.*; -import static io.netty.handler.codec.http.HttpMethod.*; -import static io.netty.handler.codec.http.HttpResponseStatus.*; -import static io.netty.handler.codec.http.HttpVersion.*; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ExceptionEvent; -import io.netty.channel.MessageEvent; -import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.handler.codec.http.DefaultHttpResponse; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.CharsetUtil; - -/** - * Handles handshakes and messages - */ -public class WebSocketServerHandler extends SimpleChannelUpstreamHandler { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class); - - private static final String WEBSOCKET_PATH = "/websocket"; - - private WebSocketServerHandshaker handshaker = null; - - @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - Object msg = e.getMessage(); - if (msg instanceof HttpRequest) { - handleHttpRequest(ctx, (HttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); - } - } - - private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { - // Allow only GET methods. - if (req.getMethod() != GET) { - sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); - return; - } - - // Send the demo page and favicon.ico - if (req.getUri().equals("/")) { - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); - - ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); - - res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); - setContentLength(res, content.readableBytes()); - - res.setContent(content); - sendHttpResponse(ctx, req, res); - return; - } else if (req.getUri().equals("/favicon.ico")) { - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); - sendHttpResponse(ctx, req, res); - return; - } - - // Handshake - WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( - this.getWebSocketLocation(req), null, false); - this.handshaker = wsFactory.newHandshaker(req); - if (this.handshaker == null) { - wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); - } else { - this.handshaker.performOpeningHandshake(ctx.getChannel(), req); - } - } - - private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { - - // Check for closing frame - if (frame instanceof CloseWebSocketFrame) { - this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame); - return; - } else if (frame instanceof PingWebSocketFrame) { - ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); - return; - } else if (!(frame instanceof TextWebSocketFrame)) { - throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() - .getName())); - } - - // Send the uppercase string back. - String request = ((TextWebSocketFrame) frame).getText(); - logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); - ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); - } - - private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { - // Generate an error page if response status code is not OK (200). - if (res.getStatus().getCode() != 200) { - res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); - setContentLength(res, res.getContent().readableBytes()); - } - - // Send the response and close the connection if necessary. - ChannelFuture f = ctx.getChannel().write(res); - if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { - f.addListener(ChannelFutureListener.CLOSE); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - e.getCause().printStackTrace(); - e.getChannel().close(); - } - - private String getWebSocketLocation(HttpRequest req) { - return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH; - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java b/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java deleted file mode 100644 index 2587e6a19d..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/server/WebSocketServerIndexPage.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.server; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.util.CharsetUtil; - - -/** - * Generates the demo HTML page which is served at http://localhost:8080/ - */ -public class WebSocketServerIndexPage { - - private static final String NEWLINE = "\r\n"; - - public static ChannelBuffer getContent(String webSocketLocation) { - return ChannelBuffers.copiedBuffer( - "Web Socket Test" + NEWLINE + - "" + NEWLINE + - "" + NEWLINE + - "
      " + NEWLINE + - "" + - "" + NEWLINE + - "

      Output

      " + NEWLINE + - "" + NEWLINE + - "
      " + NEWLINE + - "" + NEWLINE + - "" + NEWLINE, - CharsetUtil.US_ASCII); - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java b/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java deleted file mode 100644 index f5bede15d1..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.sslserver; - -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.socket.nio.NioServerSocketChannelFactory; - -/** - * A HTTP server which serves Web Socket requests at: - * - * https://localhost:8081/websocket - * - * Open your browser at https://localhost:8081/, then the demo page will be - * loaded and a Web Socket connection will be made automatically. - * - * This server illustrates support for the different web socket specification - * versions and will work with: - * - *
        - *
      • Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) - *
      • - *
      • Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) - *
      • - *
      • Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) - *
      • - *
      • Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) - *
      • - *
      - */ -public class WebSocketSslServer { - public static void main(String[] args) { - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINE); - Logger.getLogger("").addHandler(ch); - Logger.getLogger("").setLevel(Level.FINE); - - String keyStoreFilePath = System.getProperty("keystore.file.path"); - if (keyStoreFilePath == null || keyStoreFilePath.isEmpty()) { - System.out.println("ERROR: System property keystore.file.path not set. Exiting now!"); - System.exit(1); - } - - String keyStoreFilePassword = System.getProperty("keystore.file.password"); - if (keyStoreFilePassword == null || keyStoreFilePassword.isEmpty()) { - System.out.println("ERROR: System property keystore.file.password not set. Exiting now!"); - System.exit(1); - } - - // Configure the server. - ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( - Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); - - // Set up the event pipeline factory. - bootstrap.setPipelineFactory(new WebSocketSslServerPipelineFactory()); - - // Bind and start to accept incoming connections. - bootstrap.bind(new InetSocketAddress(8081)); - - System.out.println("Web Socket Server started on 8081. Open your browser and navigate to https://localhost:8081/"); - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java b/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java deleted file mode 100644 index 8274fa6354..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerHandler.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.sslserver; - -import static io.netty.handler.codec.http.HttpHeaders.*; -import static io.netty.handler.codec.http.HttpHeaders.Names.*; -import static io.netty.handler.codec.http.HttpMethod.*; -import static io.netty.handler.codec.http.HttpResponseStatus.*; -import static io.netty.handler.codec.http.HttpVersion.*; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ExceptionEvent; -import io.netty.channel.MessageEvent; -import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.handler.codec.http.DefaultHttpResponse; -import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; -import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; -import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.CharsetUtil; - -/** - * Handles handshakes and messages - */ -public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerHandler.class); - - private static final String WEBSOCKET_PATH = "/websocket"; - - private WebSocketServerHandshaker handshaker = null; - - @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - Object msg = e.getMessage(); - if (msg instanceof HttpRequest) { - handleHttpRequest(ctx, (HttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); - } - } - - private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception { - // Allow only GET methods. - if (req.getMethod() != GET) { - sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN)); - return; - } - - // Send the demo page and favicon.ico - if (req.getUri().equals("/")) { - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); - - ChannelBuffer content = WebSocketSslServerIndexPage.getContent(getWebSocketLocation(req)); - - res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8"); - setContentLength(res, content.readableBytes()); - - res.setContent(content); - sendHttpResponse(ctx, req, res); - return; - } else if (req.getUri().equals("/favicon.ico")) { - HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND); - sendHttpResponse(ctx, req, res); - return; - } - - // Handshake - WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( - this.getWebSocketLocation(req), null, false); - this.handshaker = wsFactory.newHandshaker(req); - if (this.handshaker == null) { - wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel()); - } else { - this.handshaker.performOpeningHandshake(ctx.getChannel(), req); - } - } - - private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { - - // Check for closing frame - if (frame instanceof CloseWebSocketFrame) { - this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame); - return; - } else if (frame instanceof PingWebSocketFrame) { - ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData())); - return; - } else if (!(frame instanceof TextWebSocketFrame)) { - throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass() - .getName())); - } - - // Send the uppercase string back. - String request = ((TextWebSocketFrame) frame).getText(); - logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request)); - ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); - } - - private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) { - // Generate an error page if response status code is not OK (200). - if (res.getStatus().getCode() != 200) { - res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8)); - setContentLength(res, res.getContent().readableBytes()); - } - - // Send the response and close the connection if necessary. - ChannelFuture f = ctx.getChannel().write(res); - if (!isKeepAlive(req) || res.getStatus().getCode() != 200) { - f.addListener(ChannelFutureListener.CLOSE); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - e.getCause().printStackTrace(); - e.getChannel().close(); - } - - private String getWebSocketLocation(HttpRequest req) { - return "wss://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH; - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java b/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java deleted file mode 100644 index 7c1948394c..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerIndexPage.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.sslserver; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.util.CharsetUtil; - - -/** - * Generates the demo HTML page which is served at http://localhost:8080/ - */ -public class WebSocketSslServerIndexPage { - - private static final String NEWLINE = "\r\n"; - - public static ChannelBuffer getContent(String webSocketLocation) { - return ChannelBuffers.copiedBuffer( - "Web Socket Test" + NEWLINE + - "" + NEWLINE + - "" + NEWLINE + - "
      " + NEWLINE + - "" + - "" + NEWLINE + - "

      Output

      " + NEWLINE + - "" + NEWLINE + - "
      " + NEWLINE + - "" + NEWLINE + - "" + NEWLINE, - CharsetUtil.US_ASCII); - } -} diff --git a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java b/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java deleted file mode 100644 index 74658311ab..0000000000 --- a/src/main/java/io/netty/example/http/websocketx/sslserver/WebSocketSslServerSslContext.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.http.websocketx.sslserver; - -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.Security; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; - -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; - -/** - * Creates a {@link SSLContext} for just server certificates. - */ -public class WebSocketSslServerSslContext { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketSslServerSslContext.class); - private static final String PROTOCOL = "TLS"; - private SSLContext _serverContext; - - /** - * Returns the singleton instance for this class - */ - public static WebSocketSslServerSslContext getInstance() { - return SingletonHolder.INSTANCE; - } - - /** - * SingletonHolder is loaded on the first execution of - * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE, - * not before. - * - * See http://en.wikipedia.org/wiki/Singleton_pattern - */ - private static class SingletonHolder { - - public static final WebSocketSslServerSslContext INSTANCE = new WebSocketSslServerSslContext(); - } - - /** - * Constructor for singleton - */ - private WebSocketSslServerSslContext() { - try { - // Key store (Server side certificate) - String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); - if (algorithm == null) { - algorithm = "SunX509"; - } - - SSLContext serverContext = null; - try { - String keyStoreFilePath = System.getProperty("keystore.file.path"); - String keyStoreFilePassword = System.getProperty("keystore.file.password"); - - KeyStore ks = KeyStore.getInstance("JKS"); - FileInputStream fin = new FileInputStream(keyStoreFilePath); - ks.load(fin, keyStoreFilePassword.toCharArray()); - - // Set up key manager factory to use our key store - // Assume key password is the same as the key store file - // password - KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); - kmf.init(ks, keyStoreFilePassword.toCharArray()); - - // Initialise the SSLContext to work with our key managers. - serverContext = SSLContext.getInstance(PROTOCOL); - serverContext.init(kmf.getKeyManagers(), null, null); - } catch (Exception e) { - throw new Error("Failed to initialize the server-side SSLContext", e); - } - _serverContext = serverContext; - } catch (Exception ex) { - logger.error("Error initializing SslContextManager. " + ex.getMessage(), ex); - System.exit(1); - - } - } - - /** - * Returns the server context with server side key store - */ - public SSLContext getServerContext() { - return _serverContext; - } - -} diff --git a/src/main/java/io/netty/example/iostream/IOStream.java b/src/main/java/io/netty/example/iostream/IOStream.java deleted file mode 100755 index 487a0a010f..0000000000 --- a/src/main/java/io/netty/example/iostream/IOStream.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.example.iostream; - -import io.netty.bootstrap.ClientBootstrap; -import io.netty.channel.*; -import io.netty.channel.iostream.IOStreamAddress; -import io.netty.channel.iostream.IOStreamChannelFactory; -import io.netty.handler.codec.frame.DelimiterBasedFrameDecoder; -import io.netty.handler.codec.frame.Delimiters; -import io.netty.handler.codec.string.StringDecoder; -import io.netty.handler.codec.string.StringEncoder; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * An example demonstrating the use of the {@link io.netty.channel.iostream.IOStreamChannel}. - */ -public class IOStream { - - private static volatile boolean running = true; - - public static void main(String[] args) { - - final ExecutorService executorService = Executors.newCachedThreadPool(); - final ClientBootstrap bootstrap = new ClientBootstrap(new IOStreamChannelFactory(executorService)); - - // Configure the event pipeline factory. - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override - public ChannelPipeline getPipeline() throws Exception { - DefaultChannelPipeline pipeline = new DefaultChannelPipeline(); - pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); - pipeline.addLast("decoder", new StringDecoder()); - pipeline.addLast("encoder", new StringEncoder()); - pipeline.addLast("loggingHandler", new SimpleChannelHandler() { - @Override - public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) - throws Exception { - - final String message = (String) e.getMessage(); - synchronized (System.out) { - e.getChannel().write("Message received: " + message); - } - if ("exit".equals(message)) { - IOStream.running = false; - } - super.messageReceived(ctx, e); - } - } - ); - return pipeline; - } - }); - - // Make a new connection. - ChannelFuture connectFuture = bootstrap.connect(new IOStreamAddress(System.in, System.out)); - - // Wait until the connection is made successfully. - Channel channel = connectFuture.awaitUninterruptibly().getChannel(); - - while (running) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - // Close the connection. - channel.close().awaitUninterruptibly(); - - // Shut down all thread pools to exit. - bootstrap.releaseExternalResources(); - - } - -} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java b/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java deleted file mode 100644 index 5e2eb22847..0000000000 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketClientHandshaker.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec.http.websocketx; - -import java.net.URI; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.Channel; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.util.CharsetUtil; - -/** - * Base class for web socket client handshake implementations - */ -public abstract class WebSocketClientHandshaker { - - private URI webSocketURL; - - private WebSocketSpecificationVersion version = WebSocketSpecificationVersion.UNKNOWN; - - private boolean openingHandshakeCompleted = false; - - private String subProtocolRequest = null; - - private String subProtocolResponse = null; - - /** - * - * @param webSocketURL - * @param version - * @param subProtocol - */ - public WebSocketClientHandshaker(URI webSocketURL, WebSocketSpecificationVersion version, String subProtocol) { - this.webSocketURL = webSocketURL; - this.version = version; - this.subProtocolRequest = subProtocol; - } - - /** - * Returns the URI to the web socket. e.g. "ws://myhost.com/path" - */ - public URI getWebSocketURL() { - return webSocketURL; - } - - protected void setWebSocketURL(URI webSocketURL) { - this.webSocketURL = webSocketURL; - } - - /** - * Version of the web socket specification that is being used - */ - public WebSocketSpecificationVersion getVersion() { - return version; - } - - protected void setVersion(WebSocketSpecificationVersion version) { - this.version = version; - } - - /** - * Flag to indicate if the opening handshake is complete - */ - public boolean isOpeningHandshakeCompleted() { - return openingHandshakeCompleted; - } - - protected void setOpenningHandshakeCompleted(boolean openningHandshakeCompleted) { - this.openingHandshakeCompleted = openningHandshakeCompleted; - } - - /** - * Returns the sub protocol request sent to the server as specified in the - * constructor - */ - public String getSubProtocolRequest() { - return subProtocolRequest; - } - - protected void setSubProtocolRequest(String subProtocolRequest) { - this.subProtocolRequest = subProtocolRequest; - } - - /** - * Returns the sub protocol response and sent by the server. Only available - * after end of handshake. - */ - public String getSubProtocolResponse() { - return subProtocolResponse; - } - - protected void setSubProtocolResponse(String subProtocolResponse) { - this.subProtocolResponse = subProtocolResponse; - } - - /** - * Performs the opening handshake - * - * @param channel - * Channel - */ - public abstract void performOpeningHandshake(Channel channel); - - /** - * Performs the closing handshake - * - * @param channel - * Channel - * @param response - * HTTP response containing the closing handshake details - */ - public abstract void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException; - - /** - * Performs an MD5 hash - * - * @param bytes - * Data to hash - * @return Hashed data - */ - protected byte[] md5(byte[] bytes) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - return md.digest(bytes); - } catch (NoSuchAlgorithmException e) { - throw new InternalError("MD5 not supported on this platform"); - } - } - - /** - * Performs an SHA-1 hash - * - * @param bytes - * Data to hash - * @return Hashed data - */ - protected byte[] sha1(byte[] bytes) { - try { - MessageDigest md = MessageDigest.getInstance("SHA1"); - return md.digest(bytes); - } catch (NoSuchAlgorithmException e) { - throw new InternalError("SHA-1 not supported on this platform"); - } - } - - /** - * Base 64 encoding - * - * @param bytes - * Bytes to encode - * @return encoded string - */ - protected String base64Encode(byte[] bytes) { - ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes); - return Base64.encode(hashed).toString(CharsetUtil.UTF_8); - } - - /** - * Creates some random bytes - * - * @param size - * Number of random bytes to create - * @return random bytes - */ - protected byte[] createRandomBytes(int size) { - byte[] bytes = new byte[size]; - - for (int i = 0; i < size; i++) { - bytes[i] = (byte) createRandomNumber(0, 255); - } - - return bytes; - } - - /** - * Generates a random number - * - * @param min - * Minimum value - * @param max - * Maximum value - * @return Random number - */ - protected int createRandomNumber(int min, int max) { - return (int) (Math.random() * max + min); - } -} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java b/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java deleted file mode 100644 index c2c432f7a1..0000000000 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec.http.websocketx; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.Channel; -import io.netty.handler.codec.base64.Base64; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.util.CharsetUtil; - -/** - * Base class for server side web socket opening and closing handshakes - */ -public abstract class WebSocketServerHandshaker { - - private String webSocketURL; - - private String subProtocols; - - private String[] subProtocolsArray = null; - - private WebSocketSpecificationVersion version = WebSocketSpecificationVersion.UNKNOWN; - - /** - * Constructor specifying the destination web socket location - * - * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be - * sent to this URL. - * @param subProtocols - * CSV of supported protocols. Null if sub protocols not - * supported. - */ - public WebSocketServerHandshaker(String webSocketURL, String subProtocols) { - this.webSocketURL = webSocketURL; - this.subProtocols = subProtocols; - - if (this.subProtocols != null) { - this.subProtocolsArray = subProtocols.split(","); - for (int i = 0; i < this.subProtocolsArray.length; i++) { - this.subProtocolsArray[i] = this.subProtocolsArray[i].trim(); - } - } - } - - /** - * Returns the URL of the web socket - */ - public String getWebSocketURL() { - return webSocketURL; - } - - public void setWebSocketURL(String webSocketURL) { - this.webSocketURL = webSocketURL; - } - - /** - * Returns the CSV of supported sub protocols - */ - public String getSubProtocols() { - return subProtocols; - } - - public void setSubProtocols(String subProtocols) { - this.subProtocols = subProtocols; - } - - /** - * Returns the version of the specification being supported - */ - public WebSocketSpecificationVersion getVersion() { - return version; - } - - public void setVersion(WebSocketSpecificationVersion version) { - this.version = version; - } - - /** - * Performs the opening handshake - * - * @param channel - * Channel - * @param req - * HTTP Request - * @throws NoSuchAlgorithmException - */ - public abstract void performOpeningHandshake(Channel channel, HttpRequest req); - - /** - * Performs the closing handshake - * - * @param channel - * Channel - * @param frame - * Closing Frame that was received - */ - public abstract void performClosingHandshake(Channel channel, CloseWebSocketFrame frame); - - /** - * Performs an MD5 hash - * - * @param bytes - * Data to hash - * @return Hashed data - */ - protected byte[] md5(byte[] bytes) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - return md.digest(bytes); - } catch (NoSuchAlgorithmException e) { - throw new InternalError("MD5 not supported on this platform"); - } - } - - /** - * SHA-1 hashing. Instance this we think it is not thread safe - * - * @param bytes - * byte to hash - * @return hashed - */ - protected byte[] sha1(byte[] bytes) { - try { - MessageDigest md = MessageDigest.getInstance("SHA1"); - return md.digest(bytes); - } catch (NoSuchAlgorithmException e) { - throw new InternalError("SHA-1 not supported on this platform"); - } - } - - /** - * Base 64 encoding - * - * @param bytes - * Bytes to encode - * @return encoded string - */ - protected String base64Encode(byte[] bytes) { - ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes); - return Base64.encode(hashed).toString(CharsetUtil.UTF_8); - } - - /** - * Selects the first matching supported sub protocol - * - * @param requestedSubProtocol - * CSV of protocols to be supported. e.g. "chat, superchat" - * @return First matching supported sub protocol. Null if not found. - */ - protected String selectSubProtocol(String requestedSubProtocol) { - if (requestedSubProtocol == null || this.subProtocolsArray == null) { - return null; - } - - String[] requesteSubProtocolsArray = requestedSubProtocol.split(","); - for (int i = 0; i < requesteSubProtocolsArray.length; i++) { - String requesteSubProtocol = requesteSubProtocolsArray[i].trim(); - - for (String supportedSubProtocol : this.subProtocolsArray) { - if (requesteSubProtocol.equals(supportedSubProtocol)) { - return requesteSubProtocol; - } - } - } - - // No match found - return null; - } -} diff --git a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java b/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java deleted file mode 100644 index de9aef2d69..0000000000 --- a/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerHandshakerFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.codec.http.websocketx; - -import io.netty.channel.Channel; -import io.netty.handler.codec.http.DefaultHttpResponse; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.HttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.handler.codec.http.HttpHeaders.Names; - -/** - * Instances the appropriate handshake class to use for clients - */ -public class WebSocketServerHandshakerFactory { - - private final String webSocketURL; - - private final String subProtocols; - - private boolean allowExtensions = false; - - /** - * Constructor specifying the destination web socket location - * - * @param webSocketURL - * URL for web socket communications. e.g - * "ws://myhost.com/mypath". Subsequent web socket frames will be - * sent to this URL. - * @param subProtocols - * CSV of supported protocols. Null if sub protocols not - * supported. - * @param allowExtensions - * Allow extensions to be used in the reserved bits of the web - * socket frame - */ - public WebSocketServerHandshakerFactory(String webSocketURL, String subProtocols, boolean allowExtensions) { - this.webSocketURL = webSocketURL; - this.subProtocols = subProtocols; - this.allowExtensions = allowExtensions; - } - - /** - * Instances a new handshaker - * - * @return A new WebSocketServerHandshaker for the requested web socket - * version. Null if web socket version is not supported. - */ - public WebSocketServerHandshaker newHandshaker(HttpRequest req) { - - String version = req.getHeader(Names.SEC_WEBSOCKET_VERSION); - if (version != null) { - if (version.equals("13")) { - // Version 13 of the wire protocol - assume version 17 of the - // specification. - return new WebSocketServerHandshaker17(webSocketURL, subProtocols, this.allowExtensions); - } else if (version.equals("8")) { - // Version 8 of the wire protocol - assume version 10 of the - // specification. - return new WebSocketServerHandshaker10(webSocketURL, subProtocols, this.allowExtensions); - } else { - return null; - } - } else { - // Assume version 00 where version header was not specified - return new WebSocketServerHandshaker00(webSocketURL, subProtocols); - } - } - - /** - * Return that we need cannot not support the web socket version - * - * @param channel - * Channel - */ - public void sendUnsupportedWebSocketVersionResponse(Channel channel) { - HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, new HttpResponseStatus(101, - "Switching Protocols")); - res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED); - res.setHeader(Names.SEC_WEBSOCKET_VERSION, "13"); - channel.write(res); - } - -} diff --git a/src/main/java/io/netty/handler/execution/seda/SedaExecutor.java b/src/main/java/io/netty/handler/execution/seda/SedaExecutor.java deleted file mode 100644 index cba9fca9fe..0000000000 --- a/src/main/java/io/netty/handler/execution/seda/SedaExecutor.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.execution.seda; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.Channels; -import io.netty.handler.execution.ChannelEventRunnable; -import io.netty.util.ExternalResourceReleasable; - -import java.util.concurrent.Executor; - -/** - * Abstract base class for SEDA bases {@link Executor} logic. - * - * - */ -public abstract class SedaExecutor implements Executor, ExternalResourceReleasable{ - - @Override - public void execute(Runnable command) { - ChannelEventRunnable runnable = (ChannelEventRunnable) command; - ChannelHandlerContext ctx = runnable.getContext(); - try { - // check if the event was down or upstream - if (runnable instanceof ChannelDownstreamEventRunnable) { - executeDownstream((ChannelDownstreamEventRunnable) runnable); - } else { - executeUpstream(runnable); - } - } catch (Exception e1) { - // handle exceptions - Channels.fireExceptionCaught(ctx, e1); - } - } - - /** - * Execute the given {@link ChannelDownstreamEventRunnable} which was triggerd by a downstream event - * - * @param runnable - * @throws Exception - */ - protected abstract void executeDownstream(ChannelDownstreamEventRunnable runnable) throws Exception; - - /** - * Execute the given {@link ChannelEventRunnable} which was triggered by an upstream event - * - * @param runnable - * @throws Exception - */ - protected abstract void executeUpstream(ChannelEventRunnable runnable) throws Exception; - -} diff --git a/src/main/java/io/netty/handler/execution/seda/SedaHandler.java b/src/main/java/io/netty/handler/execution/seda/SedaHandler.java deleted file mode 100644 index 71ac43f3c1..0000000000 --- a/src/main/java/io/netty/handler/execution/seda/SedaHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.execution.seda; - -import java.util.concurrent.Executor; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.execution.ExecutionHandler; - -/** - * {@link ExecutionHandler} which submit all downstream and upstream events to the given {@link SedaExecutor}. The {@link SedaExecutor} is responsible for hand of the events - * to the different {@link Executor}'s and so build up an SEDA architecture. - * - * - */ -public class SedaHandler extends ExecutionHandler { - - public SedaHandler(SedaExecutor executor) { - super(executor); - } - - @Override - public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { - handleReadSuspend(ctx, e); - getExecutor().execute(new ChannelDownstreamEventRunnable(ctx, e)); - } - - @Override - public void releaseExternalResources() { - ((SedaExecutor) getExecutor()).releaseExternalResources(); - } - -} diff --git a/src/main/java/io/netty/handler/execution/seda/SimpleSedaExecutor.java b/src/main/java/io/netty/handler/execution/seda/SimpleSedaExecutor.java deleted file mode 100644 index 17a261a236..0000000000 --- a/src/main/java/io/netty/handler/execution/seda/SimpleSedaExecutor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.execution.seda; - -import java.util.concurrent.Executor; - -import io.netty.handler.execution.ChannelEventRunnable; -import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; -import io.netty.util.internal.ExecutorUtil; - -/** - * {@link SedaExecutor} which use two different {@link Executor}'s. One is used for upstream events and one for downstream events. - * - * You should use an {@link OrderedMemoryAwareThreadPoolExecutor} if you care about the order of thread-execution. In most cases this should be the case - * - * - */ -public class SimpleSedaExecutor extends SedaExecutor{ - - private final Executor upstreamExecutor; - private final Executor downstreamExecutor; - - /** - * Constrct an {@link SimpleSedaExecutor} which use two different {@link Executor}'s. One is used for upstream events and one for downstream events. - * - * @param upstreamExecutor the {@link Executor} which is used for upstream events - * @param downstreamExecutor the {@link Executor} which is used for downstream events - */ - public SimpleSedaExecutor(Executor upstreamExecutor, Executor downstreamExecutor) { - this.upstreamExecutor = upstreamExecutor; - this.downstreamExecutor = downstreamExecutor; - } - - /** - * Construct an {@link SimpleSedaExecutor} which uses the same {@link Executor} for downstream and upstream events - * - * @param executor the {@link Executor} for events - */ - public SimpleSedaExecutor(Executor executor) { - this(executor, executor); - } - - @Override - public void releaseExternalResources() { - ExecutorUtil.terminate(upstreamExecutor, downstreamExecutor); - } - - @Override - protected void executeDownstream(ChannelDownstreamEventRunnable runnable) throws Exception { - downstreamExecutor.execute(runnable); - } - - @Override - protected void executeUpstream(ChannelEventRunnable runnable) throws Exception { - upstreamExecutor.execute(runnable); - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/CIDR.java b/src/main/java/io/netty/handler/ipfilter/CIDR.java deleted file mode 100644 index 0cc9cb20e3..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/CIDR.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.StringTokenizer; - -/** - */ -public abstract class CIDR implements Comparable -{ - /** - * The base address of the CIDR notation - */ - protected InetAddress baseAddress; - - /** - * The mask used in the CIDR notation - */ - protected int cidrMask; - - /** - * Create CIDR using the CIDR Notation - * @param baseAddress - * @param cidrMask - * @return the generated CIDR - * @throws UnknownHostException - */ - public static CIDR newCIDR(InetAddress baseAddress, int cidrMask) throws UnknownHostException - { - if (cidrMask < 0) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - if (baseAddress instanceof Inet4Address) - { - if (cidrMask > 32) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - return new CIDR4((Inet4Address) baseAddress, cidrMask); - } - // IPv6. - if (cidrMask > 128) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - return new CIDR6((Inet6Address) baseAddress, cidrMask); - } - - /** - * Create CIDR using the normal Notation - * @param baseAddress - * @param scidrMask - * @return the generated CIDR - * @throws UnknownHostException - */ - public static CIDR newCIDR(InetAddress baseAddress, String scidrMask) throws UnknownHostException - { - int cidrMask = getNetMask(scidrMask); - if (cidrMask < 0) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - if (baseAddress instanceof Inet4Address) - { - if (cidrMask > 32) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - return new CIDR4((Inet4Address) baseAddress, cidrMask); - } - cidrMask += 96; - // IPv6. - if (cidrMask > 128) - { - throw new UnknownHostException("Invalid mask length used: " + cidrMask); - } - return new CIDR6((Inet6Address) baseAddress, cidrMask); - } - - /** - * Create CIDR using the CIDR or normal Notation
      - * i.e.: - * CIDR subnet = newCIDR ("10.10.10.0/24"); or - * CIDR subnet = newCIDR ("1fff:0:0a88:85a3:0:0:ac1f:8001/24"); or - * CIDR subnet = newCIDR ("10.10.10.0/255.255.255.0"); - * @param cidr - * @return the generated CIDR - * @throws UnknownHostException - */ - public static CIDR newCIDR(String cidr) throws UnknownHostException - { - int p = cidr.indexOf("/"); - if (p < 0) - { - throw new UnknownHostException("Invalid CIDR notation used: " + cidr); - } - String addrString = cidr.substring(0, p); - String maskString = cidr.substring(p + 1); - InetAddress addr = addressStringToInet(addrString); - int mask = 0; - if (maskString.indexOf(".") < 0) - { - mask = parseInt(maskString, -1); - } - else - { - mask = getNetMask(maskString); - if (addr instanceof Inet6Address) - { - mask += 96; - } - } - if (mask < 0) - { - throw new UnknownHostException("Invalid mask length used: " + maskString); - } - return newCIDR(addr, mask); - } - - /** @return the baseAddress of the CIDR block. */ - public InetAddress getBaseAddress() - { - return baseAddress; - } - - /** @return the Mask length. */ - public int getMask() - { - return cidrMask; - } - - /** @return the textual CIDR notation. */ - @Override - public String toString() - { - return baseAddress.getHostAddress() + "/" + cidrMask; - } - - /** @return the end address of this block. */ - public abstract InetAddress getEndAddress(); - - /** - * Compares the given InetAddress against the CIDR and returns true if - * the ip is in the subnet-ip-range and false if not. - * @param inetAddress - * @return returns true if the given IP address is inside the currently - * set network. - */ - public abstract boolean contains(InetAddress inetAddress); - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object arg0) { - if (!(arg0 instanceof CIDR)) { - return false; - } - return (this.compareTo((CIDR) arg0) == 0); - } - - /** Convert an IPv4 or IPv6 textual representation into an - * InetAddress. - * @param addr - * @return the created InetAddress - * @throws UnknownHostException - */ - private static InetAddress addressStringToInet(String addr) throws UnknownHostException - { - return InetAddress.getByName(addr); - } - - /** - * Get the Subnet's Netmask in Decimal format.
      - * i.e.: getNetMask("255.255.255.0") returns the integer CIDR mask - * @param netMask a network mask - * @return the integer CIDR mask - * */ - private static int getNetMask(String netMask) - { - StringTokenizer nm = new StringTokenizer(netMask, "."); - int i = 0; - int[] netmask = new int[4]; - while (nm.hasMoreTokens()) - { - netmask[i] = Integer.parseInt(nm.nextToken()); - i++; - } - int mask1 = 0; - for (i = 0; i < 4; i++) - { - mask1 += Integer.bitCount(netmask[i]); - } - return mask1; - } - - /** @param intstr a string containing an integer. - * @param def the default if the string does not contain a valid - * integer. - * @return the inetAddress from the integer - */ - private static int parseInt(String intstr, int def) - { - Integer res; - if (intstr == null) - { - return def; - } - try - { - res = Integer.decode(intstr); - } - catch (Exception e) - { - res = new Integer(def); - } - return res.intValue(); - } - - /** - * Compute a byte representation of IpV4 from a IpV6 - * @param address - * @return the byte representation - * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 - */ - public static byte[] getIpV4FromIpV6(Inet6Address address) throws IllegalArgumentException - { - byte[] baddr = address.getAddress(); - for (int i = 0; i < 9; i++) - { - if (baddr[i] != 0) - { - throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); - } - } - if (baddr[10] != 0 && baddr[10] != 0xFF || baddr[11] != 0 && baddr[11] != 0xFF) - { - throw new IllegalArgumentException("This IPv6 address cannot be used in IPv4 context"); - } - return new byte[] - {baddr[12], baddr[13], baddr[14], baddr[15]}; - } - - /** - * Compute a byte representation of IpV6 from a IpV4 - * @param address - * @return the byte representation - * @throws IllegalArgumentException if the IpV6 cannot be mapped to IpV4 - */ - public static byte[] getIpV6FromIpV4(Inet4Address address) throws IllegalArgumentException - { - byte[] baddr = address.getAddress(); - return new byte[] - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, baddr[0], baddr[1], baddr[2], baddr[3]}; - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/CIDR4.java b/src/main/java/io/netty/handler/ipfilter/CIDR4.java deleted file mode 100644 index 9135584078..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/CIDR4.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - */ -public class CIDR4 extends CIDR -{ - /** - * The integer for the base address - */ - private int addressInt; - - /** - * The integer for the end address - */ - private final int addressEndInt; - - /** - * @param newaddr - * @param mask - */ - protected CIDR4(Inet4Address newaddr, int mask) - { - cidrMask = mask; - addressInt = ipv4AddressToInt(newaddr); - int newmask = ipv4PrefixLengthToMask(mask); - addressInt &= newmask; - try - { - baseAddress = intToIPv4Address(addressInt); - } - catch (UnknownHostException e) - { - // this should never happen - } - addressEndInt = addressInt + ipv4PrefixLengthToLength(cidrMask) - 1; - } - - @Override - public InetAddress getEndAddress() - { - try - { - return intToIPv4Address(addressEndInt); - } - catch (UnknownHostException e) - { - // this should never happen - return null; - } - } - - @Override - public int compareTo(CIDR arg) - { - if (arg instanceof CIDR6) - { - byte[] address = getIpV4FromIpV6((Inet6Address) arg.baseAddress); - int net = ipv4AddressToInt(address); - if (net == addressInt && arg.cidrMask == cidrMask) - { - return 0; - } - if (net < addressInt) - { - return 1; - } - else if (net > addressInt) - { - return -1; - } - else if (arg.cidrMask < cidrMask) - { - return -1; - } - return 1; - } - CIDR4 o = (CIDR4) arg; - if (o.addressInt == addressInt && o.cidrMask == cidrMask) - { - return 0; - } - if (o.addressInt < addressInt) - { - return 1; - } - else if (o.addressInt > addressInt) - { - return -1; - } - else if (o.cidrMask < cidrMask) - { - // greater Mask means less IpAddresses so -1 - return -1; - } - return 1; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress) - */ - @Override - public boolean contains(InetAddress inetAddress) - { - int search = ipv4AddressToInt(inetAddress); - return search >= addressInt && search <= addressEndInt; - } - - /** Given an IPv4 baseAddress length, return the block length. I.e., a - * baseAddress length of 24 will return 256. */ - private static int ipv4PrefixLengthToLength(int prefix_length) - { - return 1 << 32 - prefix_length; - } - - /** Given a baseAddress length, return a netmask. I.e, a baseAddress length - * of 24 will return 0xFFFFFF00. */ - private static int ipv4PrefixLengthToMask(int prefix_length) - { - return ~((1 << 32 - prefix_length) - 1); - } - - /** Convert an integer into an (IPv4) InetAddress. - * @param addr - * @return the created InetAddress - * @throws UnknownHostException - * @throws UnknownHostException - */ - private static InetAddress intToIPv4Address(int addr) throws UnknownHostException - { - byte[] a = new byte[4]; - a[0] = (byte) (addr >> 24 & 0xFF); - a[1] = (byte) (addr >> 16 & 0xFF); - a[2] = (byte) (addr >> 8 & 0xFF); - a[3] = (byte) (addr & 0xFF); - return InetAddress.getByAddress(a); - } - - /** Given an IPv4 address, convert it into an integer. - * @param addr - * @return the integer representation of the InetAddress - * - * @throws IllegalArgumentException if the address is really an - * IPv6 address. - */ - private static int ipv4AddressToInt(InetAddress addr) - { - byte[] address = null; - if (addr instanceof Inet6Address) - { - address = getIpV4FromIpV6((Inet6Address) addr); - } - else - { - address = addr.getAddress(); - } - return ipv4AddressToInt(address); - } - - /** Given an IPv4 address as array of bytes, convert it into an integer. - * @param address - * @return the integer representation of the InetAddress - * - * @throws IllegalArgumentException if the address is really an - * IPv6 address. - */ - private static int ipv4AddressToInt(byte[] address) - { - int net = 0; - for (byte addres : address) - { - net <<= 8; - net |= addres & 0xFF; - } - return net; - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/CIDR6.java b/src/main/java/io/netty/handler/ipfilter/CIDR6.java deleted file mode 100644 index f56bf8d6c0..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/CIDR6.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; - -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; - -/** - */ -public class CIDR6 extends CIDR -{ - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(CIDR6.class); - - /** - * The big integer for the base address - */ - private BigInteger addressBigInt; - - /** - * The big integer for the end address - */ - private final BigInteger addressEndBigInt; - - /** - * @param newaddress - * @param newmask - */ - protected CIDR6(Inet6Address newaddress, int newmask) - { - cidrMask = newmask; - addressBigInt = ipv6AddressToBigInteger(newaddress); - BigInteger mask = ipv6CidrMaskToMask(newmask); - try - { - addressBigInt = addressBigInt.and(mask); - baseAddress = bigIntToIPv6Address(addressBigInt); - } - catch (UnknownHostException e) - { - // this should never happen. - } - addressEndBigInt = addressBigInt.add(ipv6CidrMaskToBaseAddress(cidrMask)).subtract(BigInteger.ONE); - } - - @Override - public InetAddress getEndAddress() - { - try - { - return bigIntToIPv6Address(addressEndBigInt); - } - catch (UnknownHostException e) - { - logger.error("invalid ip address calculated as an end address"); - return null; - } - } - - @Override - public int compareTo(CIDR arg) - { - if (arg instanceof CIDR4) - { - BigInteger net = ipv6AddressToBigInteger(arg.baseAddress); - int res = net.compareTo(addressBigInt); - if (res == 0) - { - if (arg.cidrMask == cidrMask) - { - return 0; - } - else if (arg.cidrMask < cidrMask) - { - return -1; - } - return 1; - } - return res; - } - CIDR6 o = (CIDR6) arg; - if (o.addressBigInt.equals(addressBigInt) && o.cidrMask == cidrMask) - { - return 0; - } - int res = o.addressBigInt.compareTo(addressBigInt); - if (res == 0) - { - if (o.cidrMask < cidrMask) - { - // greater Mask means less IpAddresses so -1 - return -1; - } - return 1; - } - return res; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.CIDR#contains(java.net.InetAddress) - */ - @Override - public boolean contains(InetAddress inetAddress) - { - BigInteger search = ipv6AddressToBigInteger(inetAddress); - return search.compareTo(addressBigInt) >= 0 && search.compareTo(addressEndBigInt) <= 0; - } - - /** Given an IPv6 baseAddress length, return the block length. I.e., a - * baseAddress length of 96 will return 2**32. */ - private static BigInteger ipv6CidrMaskToBaseAddress(int cidrMask) - { - return BigInteger.ONE.shiftLeft(128 - cidrMask); - } - - private static BigInteger ipv6CidrMaskToMask(int cidrMask) - { - return BigInteger.ONE.shiftLeft(128 - cidrMask).subtract(BigInteger.ONE).not(); - } - - /** Given an IPv6 address, convert it into a BigInteger. - * @param addr - * @return the integer representation of the InetAddress - * - * @throws IllegalArgumentException if the address is not an IPv6 - * address. - */ - private static BigInteger ipv6AddressToBigInteger(InetAddress addr) - { - byte[] ipv6; - if (addr instanceof Inet4Address) - { - ipv6 = getIpV6FromIpV4((Inet4Address) addr); - } - else - { - ipv6 = addr.getAddress(); - } - if (ipv6[0] == -1) - { - return new BigInteger(1, ipv6); - } - return new BigInteger(ipv6); - } - - /** Convert a big integer into an IPv6 address. - * @param addr - * @return the inetAddress from the integer - * - * @throws UnknownHostException if the big integer is too large, - * and thus an invalid IPv6 address. - */ - private static InetAddress bigIntToIPv6Address(BigInteger addr) throws UnknownHostException - { - byte[] a = new byte[16]; - byte[] b = addr.toByteArray(); - if (b.length > 16 && !(b.length == 17 && b[0] == 0)) - { - throw new UnknownHostException("invalid IPv6 address (too big)"); - } - if (b.length == 16) - { - return InetAddress.getByAddress(b); - } - // handle the case where the IPv6 address starts with "FF". - if (b.length == 17) - { - System.arraycopy(b, 1, a, 0, 16); - } - else - { - // copy the address into a 16 byte array, zero-filled. - int p = 16 - b.length; - for (int i = 0; i < b.length; i++) - { - a[p + i] = b[i]; - } - } - return InetAddress.getByAddress(a); - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java b/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java deleted file mode 100644 index fe0be8540e..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpFilterListener.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetSocketAddress; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; - -/** - * The listener interface for receiving ipFilter events. - * - * @see IpFilteringHandler - * - - */ -public interface IpFilterListener -{ - - /** - * Called when the channel has the CONNECTED status and the channel was allowed by a previous call to accept(). - * This method enables your implementation to send a message back to the client before closing - * or whatever you need. This method returns a ChannelFuture on which the implementation - * can wait uninterruptibly before continuing.
      - * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. - * @param ctx - * @param e - * @param inetSocketAddress the remote {@link InetSocketAddress} from client - * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. - */ - ChannelFuture allowed(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); - - /** - * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). - * This method enables your implementation to send a message back to the client before closing - * or whatever you need. This method returns a ChannelFuture on which the implementation - * will wait uninterruptibly before closing the channel.
      - * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. - * @param ctx - * @param e - * @param inetSocketAddress the remote {@link InetSocketAddress} from client - * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. - */ - ChannelFuture refused(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress); - - /** - * Called in handleUpstream, if this channel was previously blocked, - * to check if whatever the event, it should be passed to the next entry in the pipeline.
      - * If one wants to not block events, just overridden this method by returning always true.

      - * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since - * those events come out before the CONNECTED event and so the possibility to filter the connection. - * @param ctx - * @param e - * @return True if the event should continue, False if the event should not continue - * since this channel was blocked by this filter - */ - boolean continues(ChannelHandlerContext ctx, ChannelEvent e); - -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java b/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java deleted file mode 100644 index 8aacdb7730..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpFilterRuleHandler.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; - -/** - * Implementation of Filter of IP based on ALLOW and DENY rules.
      - *

      - * This implementation could be changed by implementing a new {@link IpFilterRule} than default - * {@link IpV4SubnetFilterRule} (IPV4 support only), {@link IpSubnetFilterRule} (IPV4 and IPV6 support) or {@link IpFilterRule} (IP and host name string pattern support) .
      - *
      - * The check is done by going from step to step in the underlying array of IpFilterRule.
      - * Each {@link IpFilterRule} answers to the method accept if the {@link InetAddress} is accepted or not, - * according to its implementation. If an InetAddress arrives at the end of the list, as in Firewall - * usual rules, the InetAddress is therefore accepted by default.
      - *
        - *
      • If it was constructed with True as first argument, - * the IpFilterRule is an ALLOW rule (every InetAddress that fits in the rule will be accepted).
      • - *
      • If it was constructed with False as first argument, - * the IpFilterRule is a DENY rule (every InetAddress that fits in the rule will be refused).
      • - *

      - *
      - * An empty list means allow all (no limitation).

      - * For efficiency reason, you should not add/remove too frequently IpFilterRules to/from this handler. - * You should prefer to replace an entry (set method) with an ALLOW/DENY ALL IpFilterRule - * if possible.


      - * This handler should be created only once and reused on every pipeline since it handles - * a global status of what is allowed or blocked.

      - * - * Note that {@link IpSubnetFilterRule} which supports IPV4 and IPV6 should be used with as much as - * possible no mixed IP protocol. Both IPV4 and IPV6 are supported but a mix (IpFilter in IPV6 notation - * and the address from the channel in IPV4, or the reverse) can lead to wrong result. - */ -@Sharable -public class IpFilterRuleHandler extends IpFilteringHandlerImpl -{ - /** - * List of {@link IpFilterRule} - */ - private final CopyOnWriteArrayList ipFilterRuleList = new CopyOnWriteArrayList(); - - /** - * Constructor from a new list of IpFilterRule - * @param newList - */ - public IpFilterRuleHandler(List newList) - { - if (newList != null) - { - ipFilterRuleList.addAll(newList); - } - } - - /** - * Empty constructor (no IpFilterRule in the List at construction). In such a situation, - * empty list implies allow all. - */ - public IpFilterRuleHandler() - { - } - - // Below are methods directly inspired from CopyOnWriteArrayList methods - /** - * Add an ipFilterRule in the list at the end - * @param ipFilterRule - */ - public void add(IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - ipFilterRuleList.add(ipFilterRule); - } - - /** - * Add an ipFilterRule in the list at the specified position (shifting to the right other elements) - * @param index - * @param ipFilterRule - */ - public void add(int index, IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - ipFilterRuleList.add(index, ipFilterRule); - } - - /** - * Appends all of the elements in the specified collection to the end of this list, - * in the order that they are returned by the specified collection's iterator. - * @param c - */ - public void addAll(Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - ipFilterRuleList.addAll(c); - } - - /** - * Inserts all of the elements in the specified collection into this list, starting at the specified position. - * @param index - * @param c - */ - public void addAll(int index, Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - ipFilterRuleList.addAll(index, c); - } - - /** - * Append the element if not present. - * @param c - * @return the number of elements added - */ - public int addAllAbsent(Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - return ipFilterRuleList.addAllAbsent(c); - } - - /** - * Append the element if not present. - * @param ipFilterRule - * @return true if the element was added - */ - public boolean addIfAbsent(IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - return ipFilterRuleList.addIfAbsent(ipFilterRule); - } - - /** - * Clear the list - */ - public void clear() - { - ipFilterRuleList.clear(); - } - - /** - * Returns true if this list contains the specified element - * @param ipFilterRule - * @return true if this list contains the specified element - */ - public boolean contains(IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - return ipFilterRuleList.contains(ipFilterRule); - } - - /** - * Returns true if this list contains all of the elements of the specified collection - * @param c - * @return true if this list contains all of the elements of the specified collection - */ - public boolean containsAll(Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - return ipFilterRuleList.containsAll(c); - } - - /** - * Returns the element at the specified position in this list - * @param index - * @return the element at the specified position in this list - */ - public IpFilterRule get(int index) - { - return ipFilterRuleList.get(index); - } - - /** - * Returns true if this list contains no elements - * @return true if this list contains no elements - */ - public boolean isEmpty() - { - return ipFilterRuleList.isEmpty(); - } - - /** - * Remove the ipFilterRule from the list - * @param ipFilterRule - */ - public void remove(IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - ipFilterRuleList.remove(ipFilterRule); - } - - /** - * Removes the element at the specified position in this list - * @param index - * @return the element previously at the specified position - */ - public IpFilterRule remove(int index) - { - return ipFilterRuleList.remove(index); - } - - /** - * Removes from this list all of its elements that are contained in the specified collection - * @param c - */ - public void removeAll(Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - ipFilterRuleList.removeAll(c); - } - - /** - * Retains only the elements in this list that are contained in the specified collection - * @param c - */ - public void retainAll(Collection c) - { - if (c == null) - { - throw new NullPointerException("Collection can not be null"); - } - ipFilterRuleList.retainAll(c); - } - - /** - * Replaces the element at the specified position in this list with the specified element - * @param index - * @param ipFilterRule - * @return the element previously at the specified position - */ - public IpFilterRule set(int index, IpFilterRule ipFilterRule) - { - if (ipFilterRule == null) - { - throw new NullPointerException("IpFilterRule can not be null"); - } - return ipFilterRuleList.set(index, ipFilterRule); - } - - /** - * Returns the number of elements in this list. - * @return the number of elements in this list. - */ - public int size() - { - return ipFilterRuleList.size(); - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilteringHandler#accept(io.netty.channel.ChannelHandlerContext, io.netty.channel.ChannelEvent, java.net.InetSocketAddress) - */ - @Override - protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) - throws Exception - { - if (ipFilterRuleList.isEmpty()) - { - // No limitation neither in deny or allow, so accept - return true; - } - InetAddress inetAddress = inetSocketAddress.getAddress(); - Iterator iterator = ipFilterRuleList.iterator(); - IpFilterRule ipFilterRule = null; - while (iterator.hasNext()) - { - ipFilterRule = iterator.next(); - if (ipFilterRule.contains(inetAddress)) - { - // Match founds, is it a ALLOW or DENY rule - return ipFilterRule.isAllowRule(); - } - } - // No limitation founds and no allow either, but as it is like Firewall rules, it is therefore accepted - return true; - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java b/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java deleted file mode 100644 index 57a9ad9aea..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpFilterRuleList.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.UnknownHostException; -import java.util.ArrayList; - -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; - -/** - * The Class IpFilterRuleList is a helper class to generate a List of Rules from a string. - * In case of parse errors no exceptions are thrown. The error is logged. - *
      - * Rule List Syntax: - *
      - *
      - * RuleList ::= Rule[,Rule]*
      - * Rule ::= AllowRule | BlockRule
      - * AllowRule ::= +Filter
      - * BlockRule ::= -Filter
      - * Filter ::= PatternFilter | CIDRFilter
      - * PatternFilter ::= @see PatternRule
      - * CIDRFilter ::= c:CIDRFilter
      - * CIDRFilter ::= @see CIDR.newCIDR(String)
      - * 
      - *
      - * Example: allow only localhost: - *
      - * new IPFilterRuleHandler().addAll(new IpFilterRuleList("+n:localhost, -n:*")); - *
      - * - - */ -public class IpFilterRuleList extends ArrayList -{ - private static final long serialVersionUID = -6164162941749588780L; - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(IpFilterRuleList.class); - - /** - * Instantiates a new ip filter rule list. - * - * @param rules the rules - */ - public IpFilterRuleList(String rules) - { - parseRules(rules); - } - - private void parseRules(String rules) - { - String[] ruless = rules.split(","); - for (String rule : ruless) - { - parseRule(rule.trim()); - } - } - - private void parseRule(String rule) - { - if (rule == null || rule.length() == 0) - return; - if (!(rule.startsWith("+") || rule.startsWith("-"))) - { - logger.error("syntax error in ip filter rule:" + rule); - return; - } - - boolean allow = rule.startsWith("+"); - if (rule.charAt(1) == 'n' || rule.charAt(1) == 'i') - this.add(new PatternRule(allow, rule.substring(1))); - else if (rule.charAt(1) == 'c') - try - { - this.add(new IpSubnetFilterRule(allow, rule.substring(3))); - } - catch (UnknownHostException e) - { - logger.error("error parsing ip filter " + rule, e); - } - else - logger.error("syntax error in ip filter rule:" + rule); - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java b/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java deleted file mode 100644 index b082d86099..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpFilteringHandlerImpl.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetSocketAddress; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateEvent; -import io.netty.channel.ChannelUpstreamHandler; -import io.netty.channel.Channels; - -// TODO: Auto-generated Javadoc -/** - * General class that handle Ip Filtering. - * - - */ -public abstract class IpFilteringHandlerImpl implements ChannelUpstreamHandler, IpFilteringHandler -{ - - private IpFilterListener listener = null; - - /** - * Called when the channel is connected. It returns True if the corresponding connection - * is to be allowed. Else it returns False. - * @param ctx - * @param e - * @param inetSocketAddress the remote {@link InetSocketAddress} from client - * @return True if the corresponding connection is allowed, else False. - * @throws Exception - */ - protected abstract boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) - throws Exception; - - /** - * Called when the channel has the CONNECTED status and the channel was refused by a previous call to accept(). - * This method enables your implementation to send a message back to the client before closing - * or whatever you need. This method returns a ChannelFuture on which the implementation - * will wait uninterruptibly before closing the channel.
      - * For instance, If a message is sent back, the corresponding ChannelFuture has to be returned. - * @param ctx - * @param e - * @param inetSocketAddress the remote {@link InetSocketAddress} from client - * @return the associated ChannelFuture to be waited for before closing the channel. Null is allowed. - * @throws Exception - */ - protected ChannelFuture handleRefusedChannel(ChannelHandlerContext ctx, ChannelEvent e, - InetSocketAddress inetSocketAddress) throws Exception - { - if (listener == null) - return null; - return listener.refused(ctx, e, inetSocketAddress); - } - - protected ChannelFuture handleAllowedChannel(ChannelHandlerContext ctx, ChannelEvent e, - InetSocketAddress inetSocketAddress) throws Exception - { - if (listener == null) - return null; - return listener.allowed(ctx, e, inetSocketAddress); - } - - /** - * Internal method to test if the current channel is blocked. Should not be overridden. - * @param ctx - * @return True if the current channel is blocked, else False - */ - protected boolean isBlocked(ChannelHandlerContext ctx) - { - return ctx.getAttachment() != null; - } - - /** - * Called in handleUpstream, if this channel was previously blocked, - * to check if whatever the event, it should be passed to the next entry in the pipeline.
      - * If one wants to not block events, just overridden this method by returning always true.

      - * Note that OPENED and BOUND events are still passed to the next entry in the pipeline since - * those events come out before the CONNECTED event and so the possibility to filter the connection. - * @param ctx - * @param e - * @return True if the event should continue, False if the event should not continue - * since this channel was blocked by this filter - * @throws Exception - */ - protected boolean continues(ChannelHandlerContext ctx, ChannelEvent e) throws Exception - { - if (listener != null) - return listener.continues(ctx, e); - else - return false; - } - - /* (non-Javadoc) - * @see io.netty.channel.ChannelUpstreamHandler#handleUpstream(io.netty.channel.ChannelHandlerContext, io.netty.channel.ChannelEvent) - */ - @Override - public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception - { - if (e instanceof ChannelStateEvent) - { - ChannelStateEvent evt = (ChannelStateEvent) e; - switch (evt.getState()) - { - case OPEN : - case BOUND : - // Special case: OPEND and BOUND events are before CONNECTED, - // but CLOSED and UNBOUND events are after DISCONNECTED: should those events be blocked too? - if (isBlocked(ctx) && !continues(ctx, evt)) - { - // don't pass to next level since channel was blocked early - return; - } - else - { - ctx.sendUpstream(e); - return; - } - case CONNECTED : - if (evt.getValue() != null) - { - // CONNECTED - InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); - if (!accept(ctx, e, inetSocketAddress)) - { - ctx.setAttachment(Boolean.TRUE); - ChannelFuture future = handleRefusedChannel(ctx, e, inetSocketAddress); - if (future != null) - { - future.addListener(ChannelFutureListener.CLOSE); - } - else - { - Channels.close(e.getChannel()); - } - if (isBlocked(ctx) && !continues(ctx, evt)) - { - // don't pass to next level since channel was blocked early - return; - } - } - else - { - handleAllowedChannel(ctx, e, inetSocketAddress); - } - // This channel is not blocked - ctx.setAttachment(null); - } - else - { - // DISCONNECTED - if (isBlocked(ctx) && !continues(ctx, evt)) - { - // don't pass to next level since channel was blocked early - return; - } - } - break; - } - } - if (isBlocked(ctx) && !continues(ctx, e)) - { - // don't pass to next level since channel was blocked early - return; - } - // Whatever it is, if not blocked, goes to the next level - ctx.sendUpstream(e); - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilteringHandler#setIpFilterListener(io.netty.handler.ipfilter.IpFilterListener) - */ - @Override - public void setIpFilterListener(IpFilterListener listener) - { - this.listener = listener; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilteringHandler#removeIpFilterListener() - */ - @Override - public void removeIpFilterListener() - { - this.listener = null; - - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpSubnet.java b/src/main/java/io/netty/handler/ipfilter/IpSubnet.java deleted file mode 100644 index 84a1917715..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpSubnet.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * This class allows to check if an IP V4 or V6 Address is contained in a subnet.
      - * - * Supported IP V4 Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) - * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
      - *

      Example1:
      - * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
      - * System.out.println("Result: "+ ips.contains("192.168.1.123"));
      - * System.out.println("Result: "+ ips.contains(inetAddress2));
      - *
      Example1 bis:
      - * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
      - * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
      - *

      Example2:
      - * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
      - * System.out.println("Result: "+ ips.contains("192.168.1.123"));
      - * System.out.println("Result: "+ ips.contains(inetAddress2));
      - *
      Example2 bis:
      - * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
      - * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
      - *
      - * Supported IP V6 Formats for the Subnets are: a:b:c:d:e:f:g:h/NN (CIDR-Notation) - * or any IPV6 notations (like a:b:c:d::/NN, a:b:c:d:e:f:w.x.y.z/NN) - * and (InetAddress,Mask) where Mask is a integer for CIDR-notation - * and (InetAddress,subnet).
      - *

      Example1:
      - * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24");
      - * IpSubnet ips = new IpSubnet("1fff:0:0a88:85a3::/24");
      - * System.out.println("Result: "+ ips.contains("1fff:0:0a88:85a3:0:0:ac1f:8001"));
      - * System.out.println("Result: "+ ips.contains(inetAddress2));
      - *
      Example1 bis:
      - * IpSubnet ips = new IpSubnet(inetAddress, 24);
      - * where inetAddress2 is 1fff:0:0a88:85a3:0:0:ac1f:8001
      - */ -public class IpSubnet implements IpSet, Comparable -{ - /** - * Internal representation - */ - private CIDR cidr = null; - - /** - * Create IpSubnet for ALL (used for ALLOW or DENY ALL) - */ - public IpSubnet() - { - // ALLOW or DENY ALL - cidr = null; - } - - /** - * Create IpSubnet using the CIDR or normal Notation
      - * i.e.:
      - * IpSubnet subnet = new IpSubnet("10.10.10.0/24"); or
      - * IpSubnet subnet = new IpSubnet("10.10.10.0/255.255.255.0"); or
      - * IpSubnet subnet = new IpSubnet("1fff:0:0a88:85a3:0:0:0:0/24"); - * @param netAddress a network address as string. - * @throws UnknownHostException - * */ - public IpSubnet(String netAddress) throws UnknownHostException - { - cidr = CIDR.newCIDR(netAddress); - } - - /** - * Create IpSubnet using the CIDR Notation - * @param inetAddress - * @param cidrNetMask - * @throws UnknownHostException - */ - public IpSubnet(InetAddress inetAddress, int cidrNetMask) throws UnknownHostException - { - cidr = CIDR.newCIDR(inetAddress, cidrNetMask); - } - - /** - * Create IpSubnet using the normal Notation - * @param inetAddress - * @param netMask - * @throws UnknownHostException - */ - public IpSubnet(InetAddress inetAddress, String netMask) throws UnknownHostException - { - cidr = CIDR.newCIDR(inetAddress, netMask); - } - - /** - * Compares the given IP-Address against the Subnet and returns true if - * the ip is in the subnet-ip-range and false if not. - * @param ipAddr an ipaddress - * @return returns true if the given IP address is inside the currently - * set network. - * @throws UnknownHostException - * */ - public boolean contains(String ipAddr) throws UnknownHostException - { - InetAddress inetAddress1 = InetAddress.getByName(ipAddr); - return this.contains(inetAddress1); - } - - /** - * Compares the given InetAddress against the Subnet and returns true if - * the ip is in the subnet-ip-range and false if not. - * @param inetAddress - * @return returns true if the given IP address is inside the currently - * set network. - * */ - @Override -public boolean contains(InetAddress inetAddress) - { - if (cidr == null) - { - // ANY - return true; - } - return cidr.contains(inetAddress); - } - - @Override - public String toString() - { - return cidr.toString(); - } - - @Override - public boolean equals(Object o) - { - if (!(o instanceof IpSubnet)) - { - return false; - } - IpSubnet ipSubnet = (IpSubnet) o; - return ipSubnet.cidr.equals(cidr); - } - - /** - * Compare two IpSubnet - */ - @Override - public int compareTo(IpSubnet o) - { - return cidr.toString().compareTo(o.cidr.toString()); - } - - /** - * Simple test functions - * @param args - * where args[0] is the netmask (standard or CIDR notation) and optional args[1] is - * the inetAddress to test with this IpSubnet - */ - public static void main(String[] args) throws Exception - { - if (args.length != 0) - { - IpSubnet ipSubnet = null; - try - { - ipSubnet = new IpSubnet(args[0]); - } - catch (UnknownHostException e) - { - return; - } - System.out.println("IpSubnet: " + ipSubnet.toString() + " from " + ipSubnet.cidr.getBaseAddress() + " to " - + ipSubnet.cidr.getEndAddress() + " mask " + ipSubnet.cidr.getMask()); - if (args.length > 1) - { - System.out.println("Is IN: " + args[1] + " " + ipSubnet.contains(args[1])); - } - } - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java b/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java deleted file mode 100644 index f0ba8348c3..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpSubnetFilterRule.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * Ip V4 and Ip V6 filter rule.
      - *
      - * Note that mix of IPV4 and IPV6 is allowed but it is not recommended. So it is preferable to not - * mix IPV4 addresses with IPV6 rules, even if it should work. - */ -public class IpSubnetFilterRule extends IpSubnet implements IpFilterRule -{ - /** - * Is this IpV4Subnet an ALLOW or DENY rule - */ - private boolean isAllowRule = true; - - /** - * Constructor for a ALLOW or DENY ALL - * @param allow True for ALLOW, False for DENY - */ - public IpSubnetFilterRule(boolean allow) - { - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param inetAddress - * @param cidrNetMask - * @throws UnknownHostException - */ - public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) throws UnknownHostException - { - super(inetAddress, cidrNetMask); - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param inetAddress - * @param netMask - * @throws UnknownHostException - */ - public IpSubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) throws UnknownHostException - { - super(inetAddress, netMask); - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param netAddress - * @throws UnknownHostException - */ - public IpSubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException - { - super(netAddress); - isAllowRule = allow; - } - - @Override - public boolean isAllowRule() - { - return isAllowRule; - } - - @Override - public boolean isDenyRule() - { - return !isAllowRule; - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java b/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java deleted file mode 100644 index 752e6060da..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpV4Subnet.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * This class allows to check if an IP-V4-Address is contained in a subnet.
      - * Supported Formats for the Subnets are: 1.1.1.1/255.255.255.255 or 1.1.1.1/32 (CIDR-Notation) - * and (InetAddress,Mask) where Mask is a integer for CIDR-notation or a String for Standard Mask notation.
      - *

      Example1:
      - * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/24");
      - * System.out.println("Result: "+ ips.contains("192.168.1.123"));
      - * System.out.println("Result: "+ ips.contains(inetAddress2));
      - *
      Example1 bis:
      - * IpV4Subnet ips = new IpV4Subnet(inetAddress, 24);
      - * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
      - *

      Example2:
      - * IpV4Subnet ips = new IpV4Subnet("192.168.1.0/255.255.255.0");
      - * System.out.println("Result: "+ ips.contains("192.168.1.123"));
      - * System.out.println("Result: "+ ips.contains(inetAddress2));
      - *
      Example2 bis:
      - * IpV4Subnet ips = new IpV4Subnet(inetAddress, "255.255.255.0");
      - * where inetAddress is 192.168.1.0 and inetAddress2 is 192.168.1.123
      - - */ -public class IpV4Subnet implements IpSet, Comparable -{ - private static final int SUBNET_MASK = 0x80000000; - - private static final int BYTE_ADDRESS_MASK = 0xFF; - - private InetAddress inetAddress; - - private int subnet; - - private int mask; - - private int cidrMask; - - /** - * Create IpV4Subnet for ALL (used for ALLOW or DENY ALL) - */ - public IpV4Subnet() - { - // ALLOW or DENY ALL - mask = -1; - // other will be ignored - inetAddress = null; - subnet = 0; - cidrMask = 0; - } - - /** - * Create IpV4Subnet using the CIDR or normal Notation
      - * i.e.: - * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/24"); or - * IpV4Subnet subnet = new IpV4Subnet("10.10.10.0/255.255.255.0"); - * @param netAddress a network address as string. - * @throws UnknownHostException - * */ - public IpV4Subnet(String netAddress) throws UnknownHostException - { - setNetAddress(netAddress); - } - - /** - * Create IpV4Subnet using the CIDR Notation - * @param inetAddress - * @param cidrNetMask - */ - public IpV4Subnet(InetAddress inetAddress, int cidrNetMask) - { - setNetAddress(inetAddress, cidrNetMask); - } - - /** - * Create IpV4Subnet using the normal Notation - * @param inetAddress - * @param netMask - */ - public IpV4Subnet(InetAddress inetAddress, String netMask) - { - setNetAddress(inetAddress, netMask); - } - - /** - * Sets the Network Address in either CIDR or Decimal Notation.
      - * i.e.: setNetAddress("1.1.1.1/24"); or
      - * setNetAddress("1.1.1.1/255.255.255.0");
      - * @param netAddress a network address as string. - * @throws UnknownHostException - * */ - private void setNetAddress(String netAddress) throws UnknownHostException - { - Vector vec = new Vector(); - StringTokenizer st = new StringTokenizer(netAddress, "/"); - while (st.hasMoreTokens()) - { - vec.add(st.nextElement()); - } - - if (vec.get(1).toString().length() < 3) - { - setNetId(vec.get(0).toString()); - setCidrNetMask(Integer.parseInt(vec.get(1).toString())); - } - else - { - setNetId(vec.get(0).toString()); - setNetMask(vec.get(1).toString()); - } - } - - /** - * Sets the Network Address in CIDR Notation. - * @param inetAddress - * @param cidrNetMask - * */ - private void setNetAddress(InetAddress inetAddress, int cidrNetMask) - { - setNetId(inetAddress); - setCidrNetMask(cidrNetMask); - } - - /** - * Sets the Network Address in Decimal Notation. - * @param inetAddress - * @param netMask - * */ - private void setNetAddress(InetAddress inetAddress, String netMask) - { - setNetId(inetAddress); - setNetMask(netMask); - } - - /** - * Sets the BaseAdress of the Subnet.
      - * i.e.: setNetId("192.168.1.0"); - * @param netId a network ID - * @throws UnknownHostException - * */ - private void setNetId(String netId) throws UnknownHostException - { - InetAddress inetAddress1 = InetAddress.getByName(netId); - this.setNetId(inetAddress1); - } - - /** - * Compute integer representation of InetAddress - * @param inetAddress1 - * @return the integer representation - */ - private int toInt(InetAddress inetAddress1) - { - byte[] address = inetAddress1.getAddress(); - int net = 0; - for (byte addres : address) - { - net <<= 8; - net |= addres & BYTE_ADDRESS_MASK; - } - return net; - } - - /** - * Sets the BaseAdress of the Subnet. - * @param inetAddress - * */ - private void setNetId(InetAddress inetAddress) - { - this.inetAddress = inetAddress; - subnet = toInt(inetAddress); - } - - /** - * Sets the Subnet's Netmask in Decimal format.
      - * i.e.: setNetMask("255.255.255.0"); - * @param netMask a network mask - * */ - private void setNetMask(String netMask) - { - StringTokenizer nm = new StringTokenizer(netMask, "."); - int i = 0; - int[] netmask = new int[4]; - while (nm.hasMoreTokens()) - { - netmask[i] = Integer.parseInt(nm.nextToken()); - i++; - } - int mask1 = 0; - for (i = 0; i < 4; i++) - { - mask1 += Integer.bitCount(netmask[i]); - } - setCidrNetMask(mask1); - } - - /** - * Sets the CIDR Netmask
      - * i.e.: setCidrNetMask(24); - * @param cidrNetMask a netmask in CIDR notation - * */ - private void setCidrNetMask(int cidrNetMask) - { - cidrMask = cidrNetMask; - mask = SUBNET_MASK >> cidrMask - 1; - } - - /** - * Compares the given IP-Address against the Subnet and returns true if - * the ip is in the subnet-ip-range and false if not. - * @param ipAddr an ipaddress - * @return returns true if the given IP address is inside the currently - * set network. - * @throws UnknownHostException - * */ - public boolean contains(String ipAddr) throws UnknownHostException - { - InetAddress inetAddress1 = InetAddress.getByName(ipAddr); - return this.contains(inetAddress1); - } - - /** - * Compares the given InetAddress against the Subnet and returns true if - * the ip is in the subnet-ip-range and false if not. - * @param inetAddress1 - * @return returns true if the given IP address is inside the currently - * set network. - * */ - @Override -public boolean contains(InetAddress inetAddress1) - { - if (mask == -1) - { - // ANY - return true; - } - return (toInt(inetAddress1) & mask) == subnet; - } - - @Override - public String toString() - { - return inetAddress.getHostAddress() + "/" + cidrMask; - } - - @Override - public boolean equals(Object o) - { - if (!(o instanceof IpV4Subnet)) - { - return false; - } - IpV4Subnet ipV4Subnet = (IpV4Subnet) o; - return ipV4Subnet.subnet == subnet && ipV4Subnet.cidrMask == cidrMask; - } - - /** - * Compare two IpV4Subnet - */ - @Override - public int compareTo(IpV4Subnet o) - { - if (o.subnet == subnet && o.cidrMask == cidrMask) - { - return 0; - } - if (o.subnet < subnet) - { - return 1; - } - else if (o.subnet > subnet) - { - return -1; - } - else if (o.cidrMask < cidrMask) - { - // greater Mask means less IpAddresses so -1 - return -1; - } - return 1; - } - - /** - * Simple test functions - * @param args - * where args[0] is the netmask (standard or CIDR notation) and optional args[1] is - * the inetAddress to test with this IpV4Subnet - */ - public static void main(String[] args) throws Exception - { - if (args.length != 0) - { - IpV4Subnet ipV4Subnet = null; - try - { - ipV4Subnet = new IpV4Subnet(args[0]); - } - catch (UnknownHostException e) - { - return; - } - if (args.length > 1) - { - System.out.println("Is IN: " + args[1] + " " + ipV4Subnet.contains(args[1])); - } - } - } -} diff --git a/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java b/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java deleted file mode 100644 index 490eb7e82f..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/IpV4SubnetFilterRule.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - * IpV4 only Filter Rule - */ -public class IpV4SubnetFilterRule extends IpV4Subnet implements IpFilterRule -{ - /** - * Is this IpV4Subnet an ALLOW or DENY rule - */ - private boolean isAllowRule = true; - - /** - * Constructor for a ALLOW or DENY ALL - * @param allow True for ALLOW, False for DENY - */ - public IpV4SubnetFilterRule(boolean allow) - { - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param inetAddress - * @param cidrNetMask - */ - public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, int cidrNetMask) - { - super(inetAddress, cidrNetMask); - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param inetAddress - * @param netMask - */ - public IpV4SubnetFilterRule(boolean allow, InetAddress inetAddress, String netMask) - { - super(inetAddress, netMask); - isAllowRule = allow; - } - - /** - * @param allow True for ALLOW, False for DENY - * @param netAddress - * @throws UnknownHostException - */ - public IpV4SubnetFilterRule(boolean allow, String netAddress) throws UnknownHostException - { - super(netAddress); - isAllowRule = allow; - } - - @Override - public boolean isAllowRule() - { - return isAllowRule; - } - - @Override - public boolean isDenyRule() - { - return !isAllowRule; - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java b/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java deleted file mode 100644 index 50b2778f3a..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/OneIpFilterHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import io.netty.channel.ChannelEvent; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelState; -import io.netty.channel.ChannelStateEvent; - -/** - * Handler that block any new connection if there are already a currently active - * channel connected with the same InetAddress (IP).
      - *
      - * - * Take care to not change isBlocked method except if you know what you are doing - * since it is used to test if the current closed connection is to be removed - * or not from the map of currently connected channel. - */ -@Sharable -public class OneIpFilterHandler extends IpFilteringHandlerImpl -{ - /** - * HashMap of current remote connected InetAddress - */ - private final ConcurrentMap connectedSet = new ConcurrentHashMap(); - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilteringHandler#accept(io.netty.channel.ChannelHandlerContext, io.netty.channel.ChannelEvent, java.net.InetSocketAddress) - */ - @Override - protected boolean accept(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) - throws Exception - { - InetAddress inetAddress = inetSocketAddress.getAddress(); - if (connectedSet.containsKey(inetAddress)) - { - return false; - } - connectedSet.put(inetAddress, Boolean.TRUE); - return true; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilteringHandler#handleUpstream(io.netty.channel.ChannelHandlerContext, io.netty.channel.ChannelEvent) - */ - @Override - public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception - { - super.handleUpstream(ctx, e); - // Try to remove entry from Map if already exists - if (e instanceof ChannelStateEvent) - { - ChannelStateEvent evt = (ChannelStateEvent) e; - if (evt.getState() == ChannelState.CONNECTED) - { - if (evt.getValue() == null) - { - // DISCONNECTED but was this channel blocked or not - if (isBlocked(ctx)) - { - // remove inetsocketaddress from set since this channel was not blocked before - InetSocketAddress inetSocketAddress = (InetSocketAddress) e.getChannel().getRemoteAddress(); - connectedSet.remove(inetSocketAddress.getAddress()); - } - } - } - } - } - -} diff --git a/src/main/java/io/netty/handler/ipfilter/PatternRule.java b/src/main/java/io/netty/handler/ipfilter/PatternRule.java deleted file mode 100644 index 7a0836ab0d..0000000000 --- a/src/main/java/io/netty/handler/ipfilter/PatternRule.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package io.netty.handler.ipfilter; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.regex.Pattern; - -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; - -/** - * The Class PatternRule represents an IP filter rule using string patterns. - *
      - * Rule Syntax: - *
      - *
      - * Rule ::= [n|i]:address          n stands for computer name, i for ip address
      - * address ::= <regex> | localhost
      - * regex is a regular expression with '*' as multi character and '?' as single character wild card
      - * 
      - *
      - * Example: allow localhost: - *
      - * new PatternRule(true, "n:localhost") - *
      - * Example: allow local lan: - *
      - * new PatternRule(true, "i:192.168.0.*") - *
      - * Example: block all - *
      - * new PatternRule(false, "n:*") - *
      - * - - */ -public class PatternRule implements IpFilterRule, Comparable -{ - private static final InternalLogger logger = InternalLoggerFactory.getInstance(PatternRule.class); - - private Pattern ipPattern = null; - - private Pattern namePattern = null; - - private boolean isAllowRule = true; - - private boolean localhost = false; - - private String pattern = null; - - /** - * Instantiates a new pattern rule. - * - * @param allow indicates if this is an allow or block rule - * @param pattern the filter pattern - */ - public PatternRule(boolean allow, String pattern) - { - this.isAllowRule = allow; - this.pattern = pattern; - parse(pattern); - } - - /** - * returns the pattern. - * - * @return the pattern - */ - public String getPattern() - { - return this.pattern; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilterRule#isAllowRule() - */ - @Override - public boolean isAllowRule() - { - return isAllowRule; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpFilterRule#isDenyRule() - */ - @Override - public boolean isDenyRule() - { - return !isAllowRule; - } - - /* (non-Javadoc) - * @see io.netty.handler.ipfilter.IpSet#contains(java.net.InetAddress) - */ - @Override - public boolean contains(InetAddress inetAddress) - { - if (localhost) - if (isLocalhost(inetAddress)) - return true; - if (ipPattern != null) - if (ipPattern.matcher(inetAddress.getHostAddress()).matches()) - return true; - if (namePattern != null) - if (namePattern.matcher(inetAddress.getHostName()).matches()) - return true; - return false; - } - - private void parse(String pattern) - { - if (pattern == null) - return; - - String[] acls = pattern.split(","); - - String ip = ""; - String name = ""; - for (String c : acls) - { - c = c.trim(); - if (c.equals("n:localhost")) - this.localhost = true; - else if (c.startsWith("n:")) - name = addRule(name, c.substring(2)); - else if (c.startsWith("i:")) - ip = addRule(ip, c.substring(2)); - } - if (ip.length() != 0) - ipPattern = Pattern.compile(ip); - if (name.length() != 0) - namePattern = Pattern.compile(name); - - } - - private String addRule(String pattern, String rule) - { - if (rule == null || rule.length() == 0) - return pattern; - if (pattern.length() != 0) - pattern += "|"; - rule = rule.replaceAll("\\.", "\\\\."); - rule = rule.replaceAll("\\*", ".*"); - rule = rule.replaceAll("\\?", "."); - pattern += "(" + rule + ")"; - return pattern; - } - - private boolean isLocalhost(InetAddress address) - { - try - { - if (address.equals(InetAddress.getLocalHost())) - return true; - } - catch (UnknownHostException e) - { - logger.info("error getting ip of localhost", e); - } - try - { - InetAddress[] addrs = InetAddress.getAllByName("127.0.0.1"); - for (InetAddress addr : addrs) - if (addr.equals(address)) - return true; - } - catch (UnknownHostException e) - { - logger.info("error getting ip of localhost", e); - } - return false; - - } - - /* (non-Javadoc) - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - @Override - public int compareTo(Object o) - { - if (o == null) - return -1; - if (!(o instanceof PatternRule)) - return -1; - PatternRule p = (PatternRule) o; - if (p.isAllowRule() && !this.isAllowRule) - return -1; - if (this.pattern == null && p.pattern == null) - return 0; - if (this.pattern != null) - return this.pattern.compareTo(p.getPattern()); - return -1; - } - -} diff --git a/src/main/java/io/netty/util/DebugUtil.java b/src/main/java/io/netty/util/DebugUtil.java deleted file mode 100644 index 773740c083..0000000000 --- a/src/main/java/io/netty/util/DebugUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util; - -import io.netty.channel.ChannelPipeline; -import io.netty.channel.ChannelSink; -import io.netty.util.internal.SystemPropertyUtil; - -/** - * Determines if Netty is running in a debug mode or not. Please note that - * this is not a Java debug mode. You can enable Netty debug mode by - * specifying the {@code "io.netty.debug"} system property (e.g. - * {@code java -Dio.netty.debug ...}) - *

      - * If debug mode is disabled (default), the stack trace of the exceptions are - * compressed to help debugging a user application. - *

      - * If debug mode is enabled, the stack trace of the exceptions raised in - * {@link ChannelPipeline} or {@link ChannelSink} are retained as it is to help - * debugging Netty. - */ -public class DebugUtil { - - /** - * Returns {@code true} if and only if Netty debug mode is enabled. - */ - public static boolean isDebugEnabled() { - String value; - try { - value = SystemPropertyUtil.get("io.netty.debug"); - } catch (Exception e) { - value = null; - } - - if (value == null) { - return false; - } - - value = value.trim().toUpperCase(); - return !value.startsWith("N") && - !value.startsWith("F") && - !value.equals("0"); - } - - private DebugUtil() { - // Unused - } -} diff --git a/src/main/java/io/netty/util/NamedThreadFactory.java b/src/main/java/io/netty/util/NamedThreadFactory.java deleted file mode 100644 index 33fa15e084..0000000000 --- a/src/main/java/io/netty/util/NamedThreadFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util; - -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -import io.netty.channel.ChannelFactory; -import io.netty.channel.socket.nio.NioServerSocketChannelFactory; - -/** - * A {@link ThreadFactory} that creates a new {@link Thread} with the specified name and thread ID. - * This class is useful when you want to customize the name of the I/O threads: - *

      - * {@link ChannelFactory} f = new {@link NioServerSocketChannelFactory}(
      - *         {@link Executors}.{@link Executors#newCachedThreadPool(java.util.concurrent.ThreadFactory) newCachedThreadPool}(new {@link NamedThreadFactory}("myServerBoss-")),
      - *         {@link Executors}.{@link Executors#newCachedThreadPool(java.util.concurrent.ThreadFactory) newCachedThreadPool}(new {@link NamedThreadFactory}("myServerWorker-")));
      - * 
      - */ -public class NamedThreadFactory implements ThreadFactory { - - private final ThreadGroup group; - private final AtomicInteger threadId = new AtomicInteger(1); - private final String prefix; - private final boolean daemon; - private final int priority; - - /** - * Creates a new factory that creates a {@link Thread} with the specified name prefix. - * - * @param prefix the prefix of the new thread's name - */ - public NamedThreadFactory(String prefix) { - this(prefix, false, Thread.NORM_PRIORITY); - } - - /** - * Creates a new factory that creates a {@link Thread} with the specified name prefix. - * - * @param prefix the prefix of the new thread's name - * @param daemon {@code true} if the new thread is a daemon thread - * @param priority the priority of the new thread - */ - public NamedThreadFactory(String prefix, boolean daemon, int priority) { - if (prefix == null) { - throw new NullPointerException("prefix"); - } - if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { - throw new IllegalArgumentException( - "priority: " + priority + - " (expected: >= " + Thread.MIN_PRIORITY + " && <= " + Thread.MAX_PRIORITY + ')'); - } - - this.prefix = prefix; - this.daemon = daemon; - this.priority = priority; - - SecurityManager s = System.getSecurityManager(); - if (s != null) { - group = s.getThreadGroup(); - } else { - group = Thread.currentThread().getThreadGroup(); - } - } - - /** - * {@inheritDoc} The name of the thread is {@code "prefix + threadId"}. (e.g. {@code "ioThread-1"} if - * {@code prefix} is {@code "ioThread-"}. - */ - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(group, r, prefix + threadId.getAndIncrement()); - t.setDaemon(daemon); - t.setPriority(priority); - return t; - } -} diff --git a/src/main/java/io/netty/util/VirtualExecutorService.java b/src/main/java/io/netty/util/VirtualExecutorService.java deleted file mode 100644 index 3326d1b728..0000000000 --- a/src/main/java/io/netty/util/VirtualExecutorService.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util; - -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; - -import io.netty.channel.ChannelFactory; -import io.netty.channel.socket.nio.NioServerSocketChannelFactory; - - -/** - * A delegating {@link ExecutorService} with its own termination management. - *

      - * {@link VirtualExecutorService} is used when you want to inject an - * {@link ExecutorService} but you do not want to allow the explicit termination - * of threads on shutdown request. It is particularly useful when the - * {@link ExecutorService} to inject is shared by different components and - * the life cycle of the components depend on the termination of the injected - * {@link ExecutorService}. - * - *

      - * ExecutorService globalExecutor = ...;
      - * ExecutorService virtualExecutor = new {@link VirtualExecutorService}(globalExecutor);
      - *
      - * {@link ChannelFactory} factory =
      - *         new {@link NioServerSocketChannelFactory}(virtualExecutor, virtualExecutor);
      - * ...
      - *
      - * // ChannelFactory.releaseExternalResources() shuts down the executor and
      - * // interrupts the I/O threads to terminate all I/O tasks and to release all
      - * // resources acquired by ChannelFactory.
      - * factory.releaseExternalResources();
      - *
      - * // Note that globalExecutor is not shut down because VirtualExecutorService
      - * // implements its own termination management. All threads which were acquired
      - * // by ChannelFactory via VirtualExecutorService are returned to the pool.
      - * assert !globalExecutor.isShutdown();
      - * 
      - * - *

      The differences from an ordinary {@link ExecutorService}

      - * - * A shutdown request ({@link #shutdown()} or {@link #shutdownNow()}) does not - * shut down its parent {@link Executor} but simply sets its internal flag to - * reject further execution request. - *

      - * {@link #shutdownNow()} interrupts only the thread which is executing the - * task executed via {@link VirtualExecutorService}. - *

      - * {@link #awaitTermination(long, TimeUnit)} does not wait for real thread - * termination but wait until {@link VirtualExecutorService} is shut down and - * its active tasks are finished and the threads are returned to the parent - * {@link Executor}. - * @apiviz.landmark - */ -public class VirtualExecutorService extends AbstractExecutorService { - - private final Executor e; - private final ExecutorService s; - final Object startStopLock = new Object(); - volatile boolean shutdown; - Set activeThreads = new MapBackedSet(new IdentityHashMap()); - - /** - * Creates a new instance with the specified parent {@link Executor}. - */ - public VirtualExecutorService(Executor parent) { - if (parent == null) { - throw new NullPointerException("parent"); - } - - if (parent instanceof ExecutorService) { - e = null; - s = (ExecutorService) parent; - } else { - e = parent; - s = null; - } - } - - @Override - public boolean isShutdown() { - synchronized (startStopLock) { - return shutdown; - } - } - - @Override - public boolean isTerminated() { - synchronized (startStopLock) { - return shutdown && activeThreads.isEmpty(); - } - } - - @Override - public void shutdown() { - synchronized (startStopLock) { - if (shutdown) { - return; - } - shutdown = true; - } - } - - @Override - public List shutdownNow() { - synchronized (startStopLock) { - if (!isTerminated()) { - shutdown(); - for (Thread t: activeThreads) { - t.interrupt(); - } - } - } - - return Collections.emptyList(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) - throws InterruptedException { - synchronized (startStopLock) { - while (!isTerminated()) { - startStopLock.wait(TimeUnit.MILLISECONDS.convert(timeout, unit)); - } - - return isTerminated(); - } - } - - @Override - public void execute(Runnable command) { - if (command == null) { - throw new NullPointerException("command"); - } - - if (shutdown) { - throw new RejectedExecutionException(); - } - - if (s != null) { - s.execute(new ChildExecutorRunnable(command)); - } else { - e.execute(new ChildExecutorRunnable(command)); - } - } - - private class ChildExecutorRunnable implements Runnable { - - private final Runnable runnable; - - ChildExecutorRunnable(Runnable runnable) { - this.runnable = runnable; - } - - @Override - public void run() { - Thread thread = Thread.currentThread(); - synchronized (startStopLock) { - activeThreads.add(thread); - } - try { - runnable.run(); - } finally { - synchronized (startStopLock) { - boolean removed = activeThreads.remove(thread); - assert removed; - if (isTerminated()) { - startStopLock.notifyAll(); - } - } - } - } - } -} diff --git a/src/main/java/io/netty/util/internal/StackTraceSimplifier.java b/src/main/java/io/netty/util/internal/StackTraceSimplifier.java deleted file mode 100644 index 3146416dc1..0000000000 --- a/src/main/java/io/netty/util/internal/StackTraceSimplifier.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util.internal; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import io.netty.channel.DefaultChannelPipeline; -import io.netty.channel.SimpleChannelHandler; -import io.netty.channel.StaticChannelPipeline; -import io.netty.util.DebugUtil; - -/** - * Simplifies an exception stack trace by removing unnecessary - * {@link StackTraceElement}s. Please note that the stack trace simplification - * is disabled if {@linkplain DebugUtil debug mode} is turned on. - */ -public class StackTraceSimplifier { - - private static final boolean SIMPLIFY_STACK_TRACE = !DebugUtil.isDebugEnabled(); - private static final Pattern EXCLUDED_STACK_TRACE = - Pattern.compile( - "^io\\.netty\\." + - "(util\\.internal\\.DeadLockProofWorker" + - "|channel\\.(SimpleChannel(Upstream|Downstream)?Handler|(Default|Static)ChannelPipeline.*))(\\$.*)?$"); - - /** - * Removes unnecessary {@link StackTraceElement}s from the specified - * exception. {@link SimpleChannelHandler}, {@link DefaultChannelPipeline}, - * and {@link StaticChannelPipeline} will be dropped from the trace. - */ - public static void simplify(Throwable e) { - if (!SIMPLIFY_STACK_TRACE) { - return; - } - - if (e.getCause() != null) { - simplify(e.getCause()); - } - - StackTraceElement[] trace = e.getStackTrace(); - if (trace == null || trace.length == 0) { - return; - } - - // Perhaps Netty bug. Let us not strip things out. - if (EXCLUDED_STACK_TRACE.matcher(trace[0].getClassName()).matches()) { - return; - } - - List simpleTrace = - new ArrayList(trace.length); - - simpleTrace.add(trace[0]); - - // Remove unnecessary stack trace elements. - for (int i = 1; i < trace.length; i ++) { - if (EXCLUDED_STACK_TRACE.matcher(trace[i].getClassName()).matches()) { - continue; - } - simpleTrace.add(trace[i]); - } - - e.setStackTrace( - simpleTrace.toArray(new StackTraceElement[simpleTrace.size()])); - } -} diff --git a/src/site/template.vm b/src/site/template.vm deleted file mode 100644 index 6b7fbee917..0000000000 --- a/src/site/template.vm +++ /dev/null @@ -1,26 +0,0 @@ -#* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - *# - - - - $project.name - Redirecting... - - - - - Please click here if not redirected automatically. - - diff --git a/src/test/java/io/netty/channel/StaticChannelPipelineTest.java b/src/test/java/io/netty/channel/StaticChannelPipelineTest.java deleted file mode 100644 index 04d596ab83..0000000000 --- a/src/test/java/io/netty/channel/StaticChannelPipelineTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel; - -import java.util.Map; - -import junit.framework.Assert; - -import org.junit.Test; - -/** - */ -public class StaticChannelPipelineTest { - - @Test - public void testConstructionWithoutNull() { - StaticChannelPipeline p = new StaticChannelPipeline(new A(), new B()); - Map m = p.toMap(); - Assert.assertEquals(2, m.size()); - Assert.assertTrue(m.get("0") instanceof A); - Assert.assertTrue(m.get("1") instanceof B); - } - - @Test - public void testConstructionWithNull1() { - StaticChannelPipeline p = new StaticChannelPipeline(null, new A(), new B()); - Map m = p.toMap(); - Assert.assertEquals(0, m.size()); - - } - - @Test - public void testConstructionWithNull2() { - StaticChannelPipeline p = new StaticChannelPipeline(new A(), null, new B()); - Map m = p.toMap(); - Assert.assertEquals(1, m.size()); - Assert.assertTrue(m.get("0") instanceof A); - - } - - @Test - public void testConstructionWithNull() { - StaticChannelPipeline p = new StaticChannelPipeline(new A(), new B(), null); - Map m = p.toMap(); - Assert.assertEquals(2, m.size()); - Assert.assertTrue(m.get("0") instanceof A); - Assert.assertTrue(m.get("1") instanceof B); - } - - static final class A extends SimpleChannelHandler { - // Dummy - } - - static final class B extends SimpleChannelHandler { - // Dummy - } -} diff --git a/src/test/java/io/netty/channel/socket/nio/NioDatagramChannelTest.java b/src/test/java/io/netty/channel/socket/nio/NioDatagramChannelTest.java deleted file mode 100644 index ffb89db37f..0000000000 --- a/src/test/java/io/netty/channel/socket/nio/NioDatagramChannelTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.socket.nio; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; - -import io.netty.bootstrap.ConnectionlessBootstrap; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -/** - * Tests NIO (UDP) datagrams - */ -public class NioDatagramChannelTest { - private static Channel sc; - - private static InetSocketAddress inetSocketAddress; - - @BeforeClass - public static void setupChannel() { - final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory( - Executors.newCachedThreadPool()); - final ConnectionlessBootstrap sb = new ConnectionlessBootstrap(channelFactory); - inetSocketAddress = new InetSocketAddress("localhost", 9999); - sc = sb.bind(inetSocketAddress); - final SimpleHandler handler = new SimpleHandler(); - sc.getPipeline().addFirst("handler", handler); - } - - @Test - public void checkBoundPort() throws Throwable { - final InetSocketAddress socketAddress = (InetSocketAddress) sc - .getLocalAddress(); - assertEquals(9999, socketAddress.getPort()); - } - - @Test - public void sendReciveOne() throws Throwable { - final String expectedPayload = "some payload"; - sendRecive(expectedPayload); - } - - @Test - public void sendReciveMultiple() throws Throwable { - final String expectedPayload = "some payload"; - for (int i = 0; i < 1000; i ++) { - sendRecive(expectedPayload); - } - } - - public void clientBootstrap() { - final NioDatagramChannelFactory channelFactory = new NioDatagramChannelFactory( - Executors.newCachedThreadPool()); - final ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(channelFactory); - bootstrap.getPipeline().addLast("test", new SimpleHandler()); - bootstrap.setOption("tcpNoDelay", true); - bootstrap.setOption("keepAlive", true); - InetSocketAddress clientAddress = new InetSocketAddress("localhost", - 8888); - bootstrap.setOption("localAddress", clientAddress); - - ChannelFuture ccf = bootstrap.connect(inetSocketAddress); - ccf.awaitUninterruptibly(); - - Channel cc = ccf.getChannel(); - final String payload = "client payload"; - ChannelFuture write = cc.write(ChannelBuffers.wrappedBuffer(payload - .getBytes(), 0, payload.length())); - write.awaitUninterruptibly(); - } - - @AfterClass - public static void closeChannel() { - if (sc != null) { - final ChannelFuture future = sc.close(); - if (future != null) { - future.awaitUninterruptibly(); - } - } - } - - private void sendRecive(final String expectedPayload) throws IOException { - final UdpClient udpClient = new UdpClient(inetSocketAddress - .getAddress(), inetSocketAddress.getPort()); - final DatagramPacket dp = udpClient.send(expectedPayload.getBytes()); - - dp.setData(new byte[expectedPayload.length()]); - assertFalse("The payload should have been cleared", expectedPayload - .equals(new String(dp.getData()))); - - udpClient.receive(dp, 4000); - - assertEquals(expectedPayload, new String(dp.getData())); - udpClient.close(); - } - -} diff --git a/src/test/java/io/netty/channel/socket/nio/SimpleHandler.java b/src/test/java/io/netty/channel/socket/nio/SimpleHandler.java deleted file mode 100644 index f624921220..0000000000 --- a/src/test/java/io/netty/channel/socket/nio/SimpleHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.socket.nio; - -import io.netty.buffer.ChannelBuffer; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.MessageEvent; -import io.netty.channel.SimpleChannelHandler; - -/** - * A very simple channel handler - */ -public class SimpleHandler extends SimpleChannelHandler { - - /** - * Called when a message is received - * - * @param ctx The channel handler context - * @param e The message event - */ - @Override - public void messageReceived(final ChannelHandlerContext ctx, - final MessageEvent e) throws Exception { - final ChannelBuffer cb = (ChannelBuffer) e.getMessage(); - final byte[] actual = new byte[cb.readableBytes()]; - cb.getBytes(0, actual); - //System.out.println("TestHandler payload : " + new String(actual)); - ctx.sendDownstream(e); - } -} diff --git a/src/test/java/io/netty/handler/ssl/AbstractSocketSslEchoTest.java b/src/test/java/io/netty/handler/ssl/AbstractSocketSslEchoTest.java deleted file mode 100644 index 193a8c9f7c..0000000000 --- a/src/test/java/io/netty/handler/ssl/AbstractSocketSslEchoTest.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.handler.ssl; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Random; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; - -import javax.net.ssl.SSLEngine; - -import io.netty.bootstrap.ClientBootstrap; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.Channel; -import io.netty.channel.ChannelFactory; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelStateEvent; -import io.netty.channel.ExceptionEvent; -import io.netty.channel.MessageEvent; -import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.example.securechat.SecureChatSslContextFactory; -import io.netty.handler.execution.ExecutionHandler; -import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.TestUtil; -import io.netty.util.internal.ExecutorUtil; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - - -/** - */ -public abstract class AbstractSocketSslEchoTest { - static final InternalLogger logger = - InternalLoggerFactory.getInstance(AbstractSocketSslEchoTest.class); - - private static final Random random = new Random(); - static final byte[] data = new byte[1048576]; - - private static ExecutorService executor; - private static ExecutorService eventExecutor; - - static { - random.nextBytes(data); - } - - @BeforeClass - public static void init() { - executor = Executors.newCachedThreadPool(); - eventExecutor = new OrderedMemoryAwareThreadPoolExecutor(16, 0, 0); - } - - @AfterClass - public static void destroy() { - ExecutorUtil.terminate(executor, eventExecutor); - } - - protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); - protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); - - protected boolean isExecutorRequired() { - return false; - } - - @Test - public void testSslEcho() throws Throwable { - ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor)); - ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor)); - - EchoHandler sh = new EchoHandler(true); - EchoHandler ch = new EchoHandler(false); - - SSLEngine sse = SecureChatSslContextFactory.getServerContext().createSSLEngine(); - SSLEngine cse = SecureChatSslContextFactory.getClientContext().createSSLEngine(); - sse.setUseClientMode(false); - cse.setUseClientMode(true); - - // Workaround for blocking I/O transport write-write dead lock. - sb.setOption("receiveBufferSize", 1048576); - sb.setOption("receiveBufferSize", 1048576); - - sb.getPipeline().addFirst("ssl", new SslHandler(sse)); - sb.getPipeline().addLast("handler", sh); - cb.getPipeline().addFirst("ssl", new SslHandler(cse)); - cb.getPipeline().addLast("handler", ch); - - if (isExecutorRequired()) { - sb.getPipeline().addFirst("executor",new ExecutionHandler(eventExecutor)); - cb.getPipeline().addFirst("executor",new ExecutionHandler(eventExecutor)); - } - - Channel sc = sb.bind(new InetSocketAddress(0)); - int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); - ccf.awaitUninterruptibly(); - if (!ccf.isSuccess()) { - logger.error("Connection attempt failed", ccf.getCause()); - sc.close().awaitUninterruptibly(); - } - assertTrue(ccf.isSuccess()); - - Channel cc = ccf.getChannel(); - ChannelFuture hf = cc.getPipeline().get(SslHandler.class).handshake(); - hf.awaitUninterruptibly(); - if (!hf.isSuccess()) { - logger.error("Handshake failed", hf.getCause()); - sh.channel.close().awaitUninterruptibly(); - ch.channel.close().awaitUninterruptibly(); - sc.close().awaitUninterruptibly(); - } - - assertTrue(hf.isSuccess()); - - for (int i = 0; i < data.length;) { - int length = Math.min(random.nextInt(1024 * 64), data.length - i); - cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); - i += length; - } - - while (ch.counter < data.length) { - if (sh.exception.get() != null) { - break; - } - if (ch.exception.get() != null) { - break; - } - - try { - Thread.sleep(1); - } catch (InterruptedException e) { - // Ignore. - } - } - - while (sh.counter < data.length) { - if (sh.exception.get() != null) { - break; - } - if (ch.exception.get() != null) { - break; - } - - try { - Thread.sleep(1); - } catch (InterruptedException e) { - // Ignore. - } - } - - sh.channel.close().awaitUninterruptibly(); - ch.channel.close().awaitUninterruptibly(); - sc.close().awaitUninterruptibly(); - - if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { - throw sh.exception.get(); - } - if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { - throw ch.exception.get(); - } - if (sh.exception.get() != null) { - throw sh.exception.get(); - } - if (ch.exception.get() != null) { - throw ch.exception.get(); - } - } - - private static class EchoHandler extends SimpleChannelUpstreamHandler { - volatile Channel channel; - final AtomicReference exception = new AtomicReference(); - volatile int counter; - private final boolean server; - - EchoHandler(boolean server) { - this.server = server; - } - - @Override - public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) - throws Exception { - channel = e.getChannel(); - } - - @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) - throws Exception { - ChannelBuffer m = (ChannelBuffer) e.getMessage(); - byte[] actual = new byte[m.readableBytes()]; - m.getBytes(0, actual); - - int lastIdx = counter; - for (int i = 0; i < actual.length; i ++) { - assertEquals(data[i + lastIdx], actual[i]); - } - - if (channel.getParent() != null) { - channel.write(m); - } - - counter += actual.length; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) - throws Exception { - logger.warn( - "Unexpected exception from the " + - (server? "server" : "client") + " side", e.getCause()); - - exception.compareAndSet(null, e.getCause()); - e.getChannel().close(); - } - } -} diff --git a/src/test/java/io/netty/util/DebugUtilTest.java b/src/test/java/io/netty/util/DebugUtilTest.java deleted file mode 100644 index b97c6eae71..0000000000 --- a/src/test/java/io/netty/util/DebugUtilTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util; - -import static org.junit.Assert.*; - -import java.security.Permission; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - - -/** - */ -public class DebugUtilTest { - - public void shouldReturnFalseIfPropertyIsNotSet() { - assertFalse(DebugUtil.isDebugEnabled()); - } - - @Test - public void shouldReturnTrueInDebugMode() { - System.setProperty("io.netty.debug", "true"); - assertTrue(DebugUtil.isDebugEnabled()); - } - - @Test - public void shouldReturnFalseInNonDebugMode() { - System.setProperty("io.netty.debug", "false"); - assertFalse(DebugUtil.isDebugEnabled()); - } - - @Test - public void shouldNotBombOutWhenSecurityManagerIsInAction() { - System.setProperty("io.netty.debug", "true"); - System.setSecurityManager(new SecurityManager() { - @Override - public void checkPropertyAccess(String key) { - throw new SecurityException(); - } - - @Override - public void checkPermission(Permission perm, Object context) { - // Allow - } - - @Override - public void checkPermission(Permission perm) { - // Allow - } - - }); - try { - assertFalse(DebugUtil.isDebugEnabled()); - } finally { - System.setSecurityManager(null); - } - } - - @Before @After - public void cleanup() { - System.clearProperty("io.netty.debug"); - } -} diff --git a/src/test/java/io/netty/util/internal/StackTraceSimplifierTest.java b/src/test/java/io/netty/util/internal/StackTraceSimplifierTest.java deleted file mode 100644 index 3f58b475ca..0000000000 --- a/src/test/java/io/netty/util/internal/StackTraceSimplifierTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.util.internal; - -import static org.easymock.EasyMock.*; -import static org.easymock.classextension.EasyMock.*; -import static org.junit.Assert.*; - -import io.netty.buffer.ChannelBuffer; -import io.netty.channel.Channel; -import io.netty.channel.DefaultChannelPipeline; -import io.netty.channel.SimpleChannelHandler; -import org.junit.Test; - - -/** - */ -public class StackTraceSimplifierTest { - - @Test - public void testBasicSimplification() { - Exception e = new Exception(); - e.setStackTrace(new StackTraceElement[] { - new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), - new StackTraceElement("com.example.Foo", "b", null, 1), - new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), - }); - - StackTraceSimplifier.simplify(e); - - StackTraceElement[] simplified = e.getStackTrace(); - assertEquals(2, simplified.length); - assertEquals(ChannelBuffer.class.getName(), simplified[0].getClassName()); - assertEquals("com.example.Foo", simplified[1].getClassName()); - } - - @Test - public void testNestedSimplification() { - Exception e1 = new Exception(); - e1.setStackTrace(new StackTraceElement[] { - new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), - new StackTraceElement("com.example.Foo", "b", null, 1), - new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), - new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1), - }); - - Exception e2 = new Exception(e1); - e2.setStackTrace(new StackTraceElement[] { - new StackTraceElement(Channel.class.getName(), "a", null, 1), - new StackTraceElement("com.example.Bar", "b", null, 1), - new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), - new StackTraceElement(DefaultChannelPipeline.class.getName(), "d", null, 1), - }); - - StackTraceSimplifier.simplify(e2); - - StackTraceElement[] simplified1 = e1.getStackTrace(); - assertEquals(2, simplified1.length); - assertEquals(ChannelBuffer.class.getName(), simplified1[0].getClassName()); - assertEquals("com.example.Foo", simplified1[1].getClassName()); - - StackTraceElement[] simplified2 = e2.getStackTrace(); - assertEquals(2, simplified2.length); - assertEquals(Channel.class.getName(), simplified2[0].getClassName()); - assertEquals("com.example.Bar", simplified2[1].getClassName()); - } - - @Test - public void testNettyBugDetection() { - Exception e = new Exception(); - e.setStackTrace(new StackTraceElement[] { - new StackTraceElement(DefaultChannelPipeline.class.getName(), "a", null, 1), - new StackTraceElement(ChannelBuffer.class.getName(), "a", null, 1), - new StackTraceElement("com.example.Foo", "b", null, 1), - new StackTraceElement(SimpleChannelHandler.class.getName(), "c", null, 1), - }); - - StackTraceSimplifier.simplify(e); - - StackTraceElement[] simplified = e.getStackTrace(); - for (StackTraceElement ste: simplified) { - System.out.println(ste); - } - assertEquals(4, simplified.length); - } - - @Test - public void testEmptyStackTrace() { - Exception e = new Exception(); - e.setStackTrace(new StackTraceElement[0]); - - StackTraceSimplifier.simplify(e); - assertEquals(0, e.getStackTrace().length); - } - - - @Test - public void testNullStackTrace() { - Exception e = createNiceMock(Exception.class); - expect(e.getStackTrace()).andReturn(null).anyTimes(); - replay(e); - - StackTraceSimplifier.simplify(e); - assertNull(e.getStackTrace()); - verify(e); - } -} diff --git a/testsuite/pom.xml b/testsuite/pom.xml new file mode 100644 index 0000000000..3bc918d5c6 --- /dev/null +++ b/testsuite/pom.xml @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-testsuite + jar + + Netty/Testsuite + + + + ${project.groupId} + netty-handler + ${project.version} + + + + diff --git a/src/test/java/io/netty/bootstrap/AbstractSocketClientBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketClientBootstrapTest.java similarity index 84% rename from src/test/java/io/netty/bootstrap/AbstractSocketClientBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketClientBootstrapTest.java index fb80aaae2f..a362933930 100644 --- a/src/test/java/io/netty/bootstrap/AbstractSocketClientBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketClientBootstrapTest.java @@ -13,9 +13,8 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket; -import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.io.IOException; @@ -25,16 +24,19 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.easymock.EasyMock; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import io.netty.bootstrap.ClientBootstrap; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPipelineException; import io.netty.channel.ChannelPipelineFactory; -import io.netty.util.DummyHandler; -import io.netty.util.TestUtil; +import io.netty.testsuite.util.DummyHandler; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; /** @@ -83,7 +85,7 @@ public abstract class AbstractSocketClientBootstrapTest { bootstrap.setOption( "remoteAddress", new InetSocketAddress( - TestUtil.getLocalHost(), + SocketAddresses.LOCALHOST, serverSocket.socket().getLocalPort())); ChannelFuture future = bootstrap.connect(); @@ -120,7 +122,7 @@ public abstract class AbstractSocketClientBootstrapTest { bootstrap.setOption( "remoteAddress", new InetSocketAddress( - TestUtil.getLocalHost(), + SocketAddresses.LOCALHOST, serverSocket.socket().getLocalPort())); bootstrap.setOption("localAddress", new InetSocketAddress(0)); @@ -145,29 +147,29 @@ public abstract class AbstractSocketClientBootstrapTest { @Test(expected = ChannelPipelineException.class) public void testFailedPipelineInitialization() throws Exception { - ClientBootstrap bootstrap = new ClientBootstrap(createMock(ChannelFactory.class)); - ChannelPipelineFactory pipelineFactory = createMock(ChannelPipelineFactory.class); + ClientBootstrap bootstrap = new ClientBootstrap(EasyMock.createMock(ChannelFactory.class)); + ChannelPipelineFactory pipelineFactory = EasyMock.createMock(ChannelPipelineFactory.class); bootstrap.setPipelineFactory(pipelineFactory); - expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); - replay(pipelineFactory); + EasyMock.expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); + EasyMock.replay(pipelineFactory); - bootstrap.connect(new InetSocketAddress(TestUtil.getLocalHost(), 1)); + bootstrap.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, 1)); } @Test(expected = IllegalStateException.class) public void shouldHaveRemoteAddressOption() { - new ClientBootstrap(createMock(ChannelFactory.class)).connect(); + new ClientBootstrap(EasyMock.createMock(ChannelFactory.class)).connect(); } @Test(expected = NullPointerException.class) public void shouldDisallowNullRemoteAddressParameter1() { - new ClientBootstrap(createMock(ChannelFactory.class)).connect(null); + new ClientBootstrap(EasyMock.createMock(ChannelFactory.class)).connect(null); } @Test(expected = NullPointerException.class) public void shouldDisallowNullRemoteAddressParameter2() { - new ClientBootstrap(createMock(ChannelFactory.class)).connect(null, null); + new ClientBootstrap(EasyMock.createMock(ChannelFactory.class)).connect(null, null); } } diff --git a/src/test/java/io/netty/handler/codec/serialization/AbstractSocketCompatibleObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketCompatibleObjectStreamEchoTest.java similarity index 94% rename from src/test/java/io/netty/handler/codec/serialization/AbstractSocketCompatibleObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketCompatibleObjectStreamEchoTest.java index 1d0b24aa46..b9fa6ee223 100644 --- a/src/test/java/io/netty/handler/codec/serialization/AbstractSocketCompatibleObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketCompatibleObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import static org.junit.Assert.*; @@ -35,15 +35,14 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.util.TestUtil; +import io.netty.handler.codec.serialization.CompatibleObjectDecoder; +import io.netty.handler.codec.serialization.CompatibleObjectEncoder; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -/** - */ public abstract class AbstractSocketCompatibleObjectStreamEchoTest { static final Random random = new Random(); @@ -96,7 +95,7 @@ public abstract class AbstractSocketCompatibleObjectStreamEchoTest { Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); diff --git a/src/test/java/io/netty/channel/socket/AbstractSocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketEchoTest.java similarity index 96% rename from src/test/java/io/netty/channel/socket/AbstractSocketEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketEchoTest.java index b41e33999c..0540016456 100644 --- a/src/test/java/io/netty/channel/socket/AbstractSocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket; import static org.junit.Assert.*; @@ -37,15 +37,12 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.util.TestUtil; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -/** - */ public abstract class AbstractSocketEchoTest { private static final Random random = new Random(); @@ -84,7 +81,7 @@ public abstract class AbstractSocketEchoTest { Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); diff --git a/src/test/java/io/netty/handler/codec/frame/AbstractSocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketFixedLengthEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/frame/AbstractSocketFixedLengthEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketFixedLengthEchoTest.java index c9bad3eaee..f9e81e98a6 100644 --- a/src/test/java/io/netty/handler/codec/frame/AbstractSocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketFixedLengthEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.frame; +package io.netty.testsuite.transport.socket; import static org.junit.Assert.*; @@ -37,15 +37,13 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.util.TestUtil; +import io.netty.handler.codec.frame.FixedLengthFrameDecoder; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -/** - */ public abstract class AbstractSocketFixedLengthEchoTest { private static final Random random = new Random(); @@ -86,7 +84,7 @@ public abstract class AbstractSocketFixedLengthEchoTest { Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); diff --git a/src/test/java/io/netty/handler/codec/serialization/AbstractSocketObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/AbstractSocketObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketObjectStreamEchoTest.java index 2051ecea49..4e324c6c16 100644 --- a/src/test/java/io/netty/handler/codec/serialization/AbstractSocketObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import static org.junit.Assert.*; @@ -35,15 +35,14 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.ExceptionEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; -import io.netty.util.TestUtil; +import io.netty.handler.codec.serialization.ObjectDecoder; +import io.netty.handler.codec.serialization.ObjectEncoder; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -/** - */ public abstract class AbstractSocketObjectStreamEchoTest { static final Random random = new Random(); @@ -95,7 +94,7 @@ public abstract class AbstractSocketObjectStreamEchoTest { Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); diff --git a/src/test/java/io/netty/bootstrap/AbstractSocketServerBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketServerBootstrapTest.java similarity index 88% rename from src/test/java/io/netty/bootstrap/AbstractSocketServerBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketServerBootstrapTest.java index 15edd45227..63438d2be7 100644 --- a/src/test/java/io/netty/bootstrap/AbstractSocketServerBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketServerBootstrapTest.java @@ -13,9 +13,8 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket; -import static org.easymock.EasyMock.*; import static org.junit.Assert.*; import java.io.IOException; @@ -26,6 +25,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import io.netty.bootstrap.ClientBootstrap; +import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFactory; @@ -36,9 +37,11 @@ import io.netty.channel.ChildChannelStateEvent; import io.netty.channel.ServerChannelFactory; import io.netty.channel.SimpleChannelUpstreamHandler; import io.netty.channel.socket.SocketChannelConfig; -import io.netty.util.DummyHandler; -import io.netty.util.TestUtil; +import io.netty.testsuite.util.DummyHandler; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; + +import org.easymock.EasyMock; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -127,7 +130,7 @@ public abstract class AbstractSocketServerBootstrapTest { Socket socket = null; try { socket = new Socket( - TestUtil.getLocalHost(), + SocketAddresses.LOCALHOST, ((InetSocketAddress) channel.getLocalAddress()).getPort()); // Wait until the connection is open in the server side. @@ -176,25 +179,25 @@ public abstract class AbstractSocketServerBootstrapTest { @Test(expected = ChannelPipelineException.class) public void testFailedPipelineInitialization() throws Exception { - ClientBootstrap bootstrap = new ClientBootstrap(createMock(ChannelFactory.class)); - ChannelPipelineFactory pipelineFactory = createMock(ChannelPipelineFactory.class); + ClientBootstrap bootstrap = new ClientBootstrap(EasyMock.createMock(ChannelFactory.class)); + ChannelPipelineFactory pipelineFactory = EasyMock.createMock(ChannelPipelineFactory.class); bootstrap.setPipelineFactory(pipelineFactory); - expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); - replay(pipelineFactory); + EasyMock.expect(pipelineFactory.getPipeline()).andThrow(new ChannelPipelineException()); + EasyMock.replay(pipelineFactory); - bootstrap.connect(new InetSocketAddress(TestUtil.getLocalHost(), 1)); + bootstrap.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, 1)); } @Test(expected = IllegalStateException.class) public void shouldHaveLocalAddressOption() { - new ServerBootstrap(createMock(ServerChannelFactory.class)).bind(); + new ServerBootstrap(EasyMock.createMock(ServerChannelFactory.class)).bind(); } @Test(expected = NullPointerException.class) public void shouldDisallowNullLocalAddressParameter() { - new ServerBootstrap(createMock(ServerChannelFactory.class)).bind(null); + new ServerBootstrap(EasyMock.createMock(ServerChannelFactory.class)).bind(null); } private static class ParentChannelHandler extends SimpleChannelUpstreamHandler { diff --git a/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketSslEchoTest.java new file mode 100644 index 0000000000..ef9b6819fe --- /dev/null +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketSslEchoTest.java @@ -0,0 +1,649 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.testsuite.transport.socket; + +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Random; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import io.netty.bootstrap.ClientBootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.ExceptionEvent; +import io.netty.channel.MessageEvent; +import io.netty.channel.SimpleChannelUpstreamHandler; +import io.netty.handler.execution.ExecutionHandler; +import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; +import io.netty.handler.ssl.SslHandler; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.SocketAddresses; +import io.netty.util.internal.ExecutorUtil; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public abstract class AbstractSocketSslEchoTest { + static final InternalLogger logger = + InternalLoggerFactory.getInstance(AbstractSocketSslEchoTest.class); + + private static final Random random = new Random(); + static final byte[] data = new byte[1048576]; + + private static ExecutorService executor; + private static ExecutorService eventExecutor; + + static { + random.nextBytes(data); + } + + @BeforeClass + public static void init() { + executor = Executors.newCachedThreadPool(); + eventExecutor = new OrderedMemoryAwareThreadPoolExecutor(16, 0, 0); + } + + @AfterClass + public static void destroy() { + ExecutorUtil.terminate(executor, eventExecutor); + } + + protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor); + protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor); + + protected boolean isExecutorRequired() { + return false; + } + + @Test + public void testSslEcho() throws Throwable { + ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor)); + ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor)); + + EchoHandler sh = new EchoHandler(true); + EchoHandler ch = new EchoHandler(false); + + SSLEngine sse = BogusSslContextFactory.getServerContext().createSSLEngine(); + SSLEngine cse = BogusSslContextFactory.getClientContext().createSSLEngine(); + sse.setUseClientMode(false); + cse.setUseClientMode(true); + + // Workaround for blocking I/O transport write-write dead lock. + sb.setOption("receiveBufferSize", 1048576); + sb.setOption("receiveBufferSize", 1048576); + + sb.getPipeline().addFirst("ssl", new SslHandler(sse)); + sb.getPipeline().addLast("handler", sh); + cb.getPipeline().addFirst("ssl", new SslHandler(cse)); + cb.getPipeline().addLast("handler", ch); + + if (isExecutorRequired()) { + sb.getPipeline().addFirst("executor", new ExecutionHandler(eventExecutor)); + cb.getPipeline().addFirst("executor", new ExecutionHandler(eventExecutor)); + } + + Channel sc = sb.bind(new InetSocketAddress(0)); + int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); + + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); + ccf.awaitUninterruptibly(); + if (!ccf.isSuccess()) { + logger.error("Connection attempt failed", ccf.getCause()); + sc.close().awaitUninterruptibly(); + } + assertTrue(ccf.isSuccess()); + + Channel cc = ccf.getChannel(); + ChannelFuture hf = cc.getPipeline().get(SslHandler.class).handshake(); + hf.awaitUninterruptibly(); + if (!hf.isSuccess()) { + logger.error("Handshake failed", hf.getCause()); + sh.channel.close().awaitUninterruptibly(); + ch.channel.close().awaitUninterruptibly(); + sc.close().awaitUninterruptibly(); + } + + assertTrue(hf.isSuccess()); + + for (int i = 0; i < data.length;) { + int length = Math.min(random.nextInt(1024 * 64), data.length - i); + cc.write(ChannelBuffers.wrappedBuffer(data, i, length)); + i += length; + } + + while (ch.counter < data.length) { + if (sh.exception.get() != null) { + break; + } + if (ch.exception.get() != null) { + break; + } + + try { + Thread.sleep(1); + } catch (InterruptedException e) { + // Ignore. + } + } + + while (sh.counter < data.length) { + if (sh.exception.get() != null) { + break; + } + if (ch.exception.get() != null) { + break; + } + + try { + Thread.sleep(1); + } catch (InterruptedException e) { + // Ignore. + } + } + + sh.channel.close().awaitUninterruptibly(); + ch.channel.close().awaitUninterruptibly(); + sc.close().awaitUninterruptibly(); + + if (sh.exception.get() != null && !(sh.exception.get() instanceof IOException)) { + throw sh.exception.get(); + } + if (ch.exception.get() != null && !(ch.exception.get() instanceof IOException)) { + throw ch.exception.get(); + } + if (sh.exception.get() != null) { + throw sh.exception.get(); + } + if (ch.exception.get() != null) { + throw ch.exception.get(); + } + } + + private static class EchoHandler extends SimpleChannelUpstreamHandler { + volatile Channel channel; + final AtomicReference exception = new AtomicReference(); + volatile int counter; + private final boolean server; + + EchoHandler(boolean server) { + this.server = server; + } + + @Override + public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) + throws Exception { + channel = e.getChannel(); + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) + throws Exception { + ChannelBuffer m = (ChannelBuffer) e.getMessage(); + byte[] actual = new byte[m.readableBytes()]; + m.getBytes(0, actual); + + int lastIdx = counter; + for (int i = 0; i < actual.length; i ++) { + assertEquals(data[i + lastIdx], actual[i]); + } + + if (channel.getParent() != null) { + channel.write(m); + } + + counter += actual.length; + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) + throws Exception { + logger.warn( + "Unexpected exception from the " + + (server? "server" : "client") + " side", e.getCause()); + + exception.compareAndSet(null, e.getCause()); + e.getChannel().close(); + } + } + + private static class BogusSslContextFactory { + + private static final String PROTOCOL = "TLS"; + private static final SSLContext SERVER_CONTEXT; + private static final SSLContext CLIENT_CONTEXT; + + static { + String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); + if (algorithm == null) { + algorithm = "SunX509"; + } + + SSLContext serverContext = null; + SSLContext clientContext = null; + try { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(BogusKeyStore.asInputStream(), + BogusKeyStore.getKeyStorePassword()); + + // Set up key manager factory to use our key store + KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); + kmf.init(ks, BogusKeyStore.getCertificatePassword()); + + // Initialize the SSLContext to work with our key managers. + serverContext = SSLContext.getInstance(PROTOCOL); + serverContext.init(kmf.getKeyManagers(), null, null); + } catch (Exception e) { + throw new Error( + "Failed to initialize the server-side SSLContext", e); + } + + try { + clientContext = SSLContext.getInstance(PROTOCOL); + clientContext.init(null, BogusTrustManagerFactory.getTrustManagers(), null); + } catch (Exception e) { + throw new Error( + "Failed to initialize the client-side SSLContext", e); + } + + SERVER_CONTEXT = serverContext; + CLIENT_CONTEXT = clientContext; + } + + public static SSLContext getServerContext() { + return SERVER_CONTEXT; + } + + public static SSLContext getClientContext() { + return CLIENT_CONTEXT; + } + } + + /** + * Bogus {@link javax.net.ssl.TrustManagerFactorySpi} which accepts any certificate + * even if it is invalid. + */ + private static class BogusTrustManagerFactory extends TrustManagerFactorySpi { + + private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + @Override + public void checkClientTrusted( + X509Certificate[] chain, String authType) throws CertificateException { + // Always trust - it is an example. + // You should do something in the real world. + // You will reach here only if you enabled client certificate auth, + // as described in SecureChatSslContextFactory. + System.err.println( + "UNKNOWN CLIENT CERTIFICATE: " + chain[0].getSubjectDN()); + } + + @Override + public void checkServerTrusted( + X509Certificate[] chain, String authType) throws CertificateException { + // Always trust - it is an example. + // You should do something in the real world. + System.err.println( + "UNKNOWN SERVER CERTIFICATE: " + chain[0].getSubjectDN()); + } + }; + + public static TrustManager[] getTrustManagers() { + return new TrustManager[] { DUMMY_TRUST_MANAGER }; + } + + @Override + protected TrustManager[] engineGetTrustManagers() { + return getTrustManagers(); + } + + @Override + protected void engineInit(KeyStore keystore) throws KeyStoreException { + // Unused + } + + @Override + protected void engineInit(ManagerFactoryParameters managerFactoryParameters) + throws InvalidAlgorithmParameterException { + // Unused + } + } + + /** + * A bogus key store which provides all the required information to + * create an example SSL connection. + * + * To generate a bogus key store: + *

      +     * keytool  -genkey -alias bogus -keysize 2048 -validity 36500
      +     *          -keyalg RSA -dname "CN=bogus"
      +     *          -keypass secret -storepass secret
      +     *          -keystore cert.jks
      +     * 
      + */ + private static final class BogusKeyStore { + private static final short[] DATA = { + 0xfe, 0xed, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x00, 0x00, 0x01, 0x1a, 0x9f, 0x57, 0xa5, + 0x27, 0x00, 0x00, 0x01, 0x9a, 0x30, 0x82, 0x01, + 0x96, 0x30, 0x0e, 0x06, 0x0a, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x2a, 0x02, 0x11, 0x01, 0x01, 0x05, + 0x00, 0x04, 0x82, 0x01, 0x82, 0x48, 0x6d, 0xcf, + 0x16, 0xb5, 0x50, 0x95, 0x36, 0xbf, 0x47, 0x27, + 0x50, 0x58, 0x0d, 0xa2, 0x52, 0x7e, 0x25, 0xab, + 0x14, 0x1a, 0x26, 0x5e, 0x2d, 0x8a, 0x23, 0x90, + 0x60, 0x7f, 0x12, 0x20, 0x56, 0xd1, 0x43, 0xa2, + 0x6b, 0x47, 0x5d, 0xed, 0x9d, 0xd4, 0xe5, 0x83, + 0x28, 0x89, 0xc2, 0x16, 0x4c, 0x76, 0x06, 0xad, + 0x8e, 0x8c, 0x29, 0x1a, 0x9b, 0x0f, 0xdd, 0x60, + 0x4b, 0xb4, 0x62, 0x82, 0x9e, 0x4a, 0x63, 0x83, + 0x2e, 0xd2, 0x43, 0x78, 0xc2, 0x32, 0x1f, 0x60, + 0xa9, 0x8a, 0x7f, 0x0f, 0x7c, 0xa6, 0x1d, 0xe6, + 0x92, 0x9e, 0x52, 0xc7, 0x7d, 0xbb, 0x35, 0x3b, + 0xaa, 0x89, 0x73, 0x4c, 0xfb, 0x99, 0x54, 0x97, + 0x99, 0x28, 0x6e, 0x66, 0x5b, 0xf7, 0x9b, 0x7e, + 0x6d, 0x8a, 0x2f, 0xfa, 0xc3, 0x1e, 0x71, 0xb9, + 0xbd, 0x8f, 0xc5, 0x63, 0x25, 0x31, 0x20, 0x02, + 0xff, 0x02, 0xf0, 0xc9, 0x2c, 0xdd, 0x3a, 0x10, + 0x30, 0xab, 0xe5, 0xad, 0x3d, 0x1a, 0x82, 0x77, + 0x46, 0xed, 0x03, 0x38, 0xa4, 0x73, 0x6d, 0x36, + 0x36, 0x33, 0x70, 0xb2, 0x63, 0x20, 0xca, 0x03, + 0xbf, 0x5a, 0xf4, 0x7c, 0x35, 0xf0, 0x63, 0x1a, + 0x12, 0x33, 0x12, 0x58, 0xd9, 0xa2, 0x63, 0x6b, + 0x63, 0x82, 0x41, 0x65, 0x70, 0x37, 0x4b, 0x99, + 0x04, 0x9f, 0xdd, 0x5e, 0x07, 0x01, 0x95, 0x9f, + 0x36, 0xe8, 0xc3, 0x66, 0x2a, 0x21, 0x69, 0x68, + 0x40, 0xe6, 0xbc, 0xbb, 0x85, 0x81, 0x21, 0x13, + 0xe6, 0xa4, 0xcf, 0xd3, 0x67, 0xe3, 0xfd, 0x75, + 0xf0, 0xdf, 0x83, 0xe0, 0xc5, 0x36, 0x09, 0xac, + 0x1b, 0xd4, 0xf7, 0x2a, 0x23, 0x57, 0x1c, 0x5c, + 0x0f, 0xf4, 0xcf, 0xa2, 0xcf, 0xf5, 0xbd, 0x9c, + 0x69, 0x98, 0x78, 0x3a, 0x25, 0xe4, 0xfd, 0x85, + 0x11, 0xcc, 0x7d, 0xef, 0xeb, 0x74, 0x60, 0xb1, + 0xb7, 0xfb, 0x1f, 0x0e, 0x62, 0xff, 0xfe, 0x09, + 0x0a, 0xc3, 0x80, 0x2f, 0x10, 0x49, 0x89, 0x78, + 0xd2, 0x08, 0xfa, 0x89, 0x22, 0x45, 0x91, 0x21, + 0xbc, 0x90, 0x3e, 0xad, 0xb3, 0x0a, 0xb4, 0x0e, + 0x1c, 0xa1, 0x93, 0x92, 0xd8, 0x72, 0x07, 0x54, + 0x60, 0xe7, 0x91, 0xfc, 0xd9, 0x3c, 0xe1, 0x6f, + 0x08, 0xe4, 0x56, 0xf6, 0x0b, 0xb0, 0x3c, 0x39, + 0x8a, 0x2d, 0x48, 0x44, 0x28, 0x13, 0xca, 0xe9, + 0xf7, 0xa3, 0xb6, 0x8a, 0x5f, 0x31, 0xa9, 0x72, + 0xf2, 0xde, 0x96, 0xf2, 0xb1, 0x53, 0xb1, 0x3e, + 0x24, 0x57, 0xfd, 0x18, 0x45, 0x1f, 0xc5, 0x33, + 0x1b, 0xa4, 0xe8, 0x21, 0xfa, 0x0e, 0xb2, 0xb9, + 0xcb, 0xc7, 0x07, 0x41, 0xdd, 0x2f, 0xb6, 0x6a, + 0x23, 0x18, 0xed, 0xc1, 0xef, 0xe2, 0x4b, 0xec, + 0xc9, 0xba, 0xfb, 0x46, 0x43, 0x90, 0xd7, 0xb5, + 0x68, 0x28, 0x31, 0x2b, 0x8d, 0xa8, 0x51, 0x63, + 0xf7, 0x53, 0x99, 0x19, 0x68, 0x85, 0x66, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x05, 0x58, 0x2e, 0x35, + 0x30, 0x39, 0x00, 0x00, 0x02, 0x3a, 0x30, 0x82, + 0x02, 0x36, 0x30, 0x82, 0x01, 0xe0, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x59, 0xf1, + 0x92, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x30, 0x81, 0xa0, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, 0x52, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, 0x67, + 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0b, + 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, 0x6d, + 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, 0x68, + 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, 0x20, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x0f, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, + 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, + 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x30, + 0x38, 0x30, 0x36, 0x31, 0x39, 0x30, 0x35, 0x34, + 0x31, 0x33, 0x38, 0x5a, 0x18, 0x0f, 0x32, 0x31, + 0x38, 0x37, 0x31, 0x31, 0x32, 0x34, 0x30, 0x35, + 0x34, 0x31, 0x33, 0x38, 0x5a, 0x30, 0x81, 0xa0, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, + 0x4b, 0x79, 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, + 0x64, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, + 0x6e, 0x67, 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, + 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, + 0x65, 0x74, 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0f, 0x45, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x31, 0x30, + 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, + 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x74, + 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, 0x79, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, + 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xc3, 0xe3, 0x5e, 0x41, 0xa7, 0x87, 0x11, + 0x00, 0x42, 0x2a, 0xb0, 0x4b, 0xed, 0xb2, 0xe0, + 0x23, 0xdb, 0xb1, 0x3d, 0x58, 0x97, 0x35, 0x60, + 0x0b, 0x82, 0x59, 0xd3, 0x00, 0xea, 0xd4, 0x61, + 0xb8, 0x79, 0x3f, 0xb6, 0x3c, 0x12, 0x05, 0x93, + 0x2e, 0x9a, 0x59, 0x68, 0x14, 0x77, 0x3a, 0xc8, + 0x50, 0x25, 0x57, 0xa4, 0x49, 0x18, 0x63, 0x41, + 0xf0, 0x2d, 0x28, 0xec, 0x06, 0xfb, 0xb4, 0x9f, + 0xbf, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, + 0x65, 0x6c, 0x30, 0x01, 0xc2, 0x8e, 0x3e, 0xcb, + 0xb3, 0x77, 0x48, 0xe9, 0x66, 0x61, 0x9a, 0x40, + 0x86, 0xaf, 0xf6, 0x03, 0xeb, 0xba, 0x6a, 0xf2, + 0xfd, 0xe2, 0xaf, 0x36, 0x5e, 0x7b, 0xaa, 0x22, + 0x04, 0xdd, 0x2c, 0x20, 0xc4, 0xfc, 0xdd, 0xd0, + 0x82, 0x20, 0x1c, 0x3d, 0xd7, 0x9e, 0x5e, 0x5c, + 0x92, 0x5a, 0x76, 0x71, 0x28, 0xf5, 0x07, 0x7d, + 0xa2, 0x81, 0xba, 0x77, 0x9f, 0x2a, 0xd9, 0x44, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x6d, 0x79, + 0x6b, 0x65, 0x79, 0x00, 0x00, 0x01, 0x1a, 0x9f, + 0x5b, 0x56, 0xa0, 0x00, 0x00, 0x01, 0x99, 0x30, + 0x82, 0x01, 0x95, 0x30, 0x0e, 0x06, 0x0a, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0x2a, 0x02, 0x11, 0x01, + 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x81, 0x29, + 0xa8, 0xb6, 0x08, 0x0c, 0x85, 0x75, 0x3e, 0xdd, + 0xb5, 0xe5, 0x1a, 0x87, 0x68, 0xd1, 0x90, 0x4b, + 0x29, 0x31, 0xee, 0x90, 0xbc, 0x9d, 0x73, 0xa0, + 0x3f, 0xe9, 0x0b, 0xa4, 0xef, 0x30, 0x9b, 0x36, + 0x9a, 0xb2, 0x54, 0x77, 0x81, 0x07, 0x4b, 0xaa, + 0xa5, 0x77, 0x98, 0xe1, 0xeb, 0xb5, 0x7c, 0x4e, + 0x48, 0xd5, 0x08, 0xfc, 0x2c, 0x36, 0xe2, 0x65, + 0x03, 0xac, 0xe5, 0xf3, 0x96, 0xb7, 0xd0, 0xb5, + 0x3b, 0x92, 0xe4, 0x14, 0x05, 0x7a, 0x6a, 0x92, + 0x56, 0xfe, 0x4e, 0xab, 0xd3, 0x0e, 0x32, 0x04, + 0x22, 0x22, 0x74, 0x47, 0x7d, 0xec, 0x21, 0x99, + 0x30, 0x31, 0x64, 0x46, 0x64, 0x9b, 0xc7, 0x13, + 0xbf, 0xbe, 0xd0, 0x31, 0x49, 0xe7, 0x3c, 0xbf, + 0xba, 0xb1, 0x20, 0xf9, 0x42, 0xf4, 0xa9, 0xa9, + 0xe5, 0x13, 0x65, 0x32, 0xbf, 0x7c, 0xcc, 0x91, + 0xd3, 0xfd, 0x24, 0x47, 0x0b, 0xe5, 0x53, 0xad, + 0x50, 0x30, 0x56, 0xd1, 0xfa, 0x9c, 0x37, 0xa8, + 0xc1, 0xce, 0xf6, 0x0b, 0x18, 0xaa, 0x7c, 0xab, + 0xbd, 0x1f, 0xdf, 0xe4, 0x80, 0xb8, 0xa7, 0xe0, + 0xad, 0x7d, 0x50, 0x74, 0xf1, 0x98, 0x78, 0xbc, + 0x58, 0xb9, 0xc2, 0x52, 0xbe, 0xd2, 0x5b, 0x81, + 0x94, 0x83, 0x8f, 0xb9, 0x4c, 0xee, 0x01, 0x2b, + 0x5e, 0xc9, 0x6e, 0x9b, 0xf5, 0x63, 0x69, 0xe4, + 0xd8, 0x0b, 0x47, 0xd8, 0xfd, 0xd8, 0xe0, 0xed, + 0xa8, 0x27, 0x03, 0x74, 0x1e, 0x5d, 0x32, 0xe6, + 0x5c, 0x63, 0xc2, 0xfb, 0x3f, 0xee, 0xb4, 0x13, + 0xc6, 0x0e, 0x6e, 0x74, 0xe0, 0x22, 0xac, 0xce, + 0x79, 0xf9, 0x43, 0x68, 0xc1, 0x03, 0x74, 0x2b, + 0xe1, 0x18, 0xf8, 0x7f, 0x76, 0x9a, 0xea, 0x82, + 0x3f, 0xc2, 0xa6, 0xa7, 0x4c, 0xfe, 0xae, 0x29, + 0x3b, 0xc1, 0x10, 0x7c, 0xd5, 0x77, 0x17, 0x79, + 0x5f, 0xcb, 0xad, 0x1f, 0xd8, 0xa1, 0xfd, 0x90, + 0xe1, 0x6b, 0xb2, 0xef, 0xb9, 0x41, 0x26, 0xa4, + 0x0b, 0x4f, 0xc6, 0x83, 0x05, 0x6f, 0xf0, 0x64, + 0x40, 0xe1, 0x44, 0xc4, 0xf9, 0x40, 0x2b, 0x3b, + 0x40, 0xdb, 0xaf, 0x35, 0xa4, 0x9b, 0x9f, 0xc4, + 0x74, 0x07, 0xe5, 0x18, 0x60, 0xc5, 0xfe, 0x15, + 0x0e, 0x3a, 0x25, 0x2a, 0x11, 0xee, 0x78, 0x2f, + 0xb8, 0xd1, 0x6e, 0x4e, 0x3c, 0x0a, 0xb5, 0xb9, + 0x40, 0x86, 0x27, 0x6d, 0x8f, 0x53, 0xb7, 0x77, + 0x36, 0xec, 0x5d, 0xed, 0x32, 0x40, 0x43, 0x82, + 0xc3, 0x52, 0x58, 0xc4, 0x26, 0x39, 0xf3, 0xb3, + 0xad, 0x58, 0xab, 0xb7, 0xf7, 0x8e, 0x0e, 0xba, + 0x8e, 0x78, 0x9d, 0xbf, 0x58, 0x34, 0xbd, 0x77, + 0x73, 0xa6, 0x50, 0x55, 0x00, 0x60, 0x26, 0xbf, + 0x6d, 0xb4, 0x98, 0x8a, 0x18, 0x83, 0x89, 0xf8, + 0xcd, 0x0d, 0x49, 0x06, 0xae, 0x51, 0x6e, 0xaf, + 0xbd, 0xe2, 0x07, 0x13, 0xd8, 0x64, 0xcc, 0xbf, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x58, 0x2e, + 0x35, 0x30, 0x39, 0x00, 0x00, 0x02, 0x34, 0x30, + 0x82, 0x02, 0x30, 0x30, 0x82, 0x01, 0xda, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x59, + 0xf2, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x9d, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4b, + 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, 0x75, 0x6e, + 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, 0x31, 0x14, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, + 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, 0x6e, 0x61, + 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x54, + 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x74, 0x79, + 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x73, 0x31, + 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, 0x78, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, 0x65, 0x74, + 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, 0x61, 0x6d, + 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6e, 0x65, + 0x74, 0x30, 0x20, 0x17, 0x0d, 0x30, 0x38, 0x30, + 0x36, 0x31, 0x39, 0x30, 0x35, 0x34, 0x35, 0x34, + 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x38, 0x37, + 0x31, 0x31, 0x32, 0x33, 0x30, 0x35, 0x34, 0x35, + 0x34, 0x30, 0x5a, 0x30, 0x81, 0x9d, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x4b, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4b, 0x79, + 0x75, 0x6e, 0x67, 0x67, 0x69, 0x2d, 0x64, 0x6f, + 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x13, 0x0b, 0x53, 0x65, 0x6f, 0x6e, 0x67, + 0x6e, 0x61, 0x6d, 0x2d, 0x73, 0x69, 0x31, 0x1a, + 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x11, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, + 0x74, 0x79, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x13, 0x0c, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, + 0x73, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x27, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x65, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6e, + 0x65, 0x74, 0x74, 0x79, 0x2e, 0x67, 0x6c, 0x65, + 0x61, 0x6d, 0x79, 0x6e, 0x6f, 0x64, 0x65, 0x2e, + 0x6e, 0x65, 0x74, 0x30, 0x5c, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, + 0x48, 0x02, 0x41, 0x00, 0x95, 0xb3, 0x47, 0x17, + 0x95, 0x0f, 0x57, 0xcf, 0x66, 0x72, 0x0a, 0x7e, + 0x5b, 0x54, 0xea, 0x8c, 0x6f, 0x79, 0xde, 0x94, + 0xac, 0x0b, 0x5a, 0xd4, 0xd6, 0x1b, 0x58, 0x12, + 0x1a, 0x16, 0x3d, 0xfe, 0xdf, 0xa5, 0x2b, 0x86, + 0xbc, 0x64, 0xd4, 0x80, 0x1e, 0x3f, 0xf9, 0xe2, + 0x04, 0x03, 0x79, 0x9b, 0xc1, 0x5c, 0xf0, 0xf1, + 0xf3, 0xf1, 0xe3, 0xbf, 0x3f, 0xc0, 0x1f, 0xdd, + 0xdb, 0xc0, 0x5b, 0x21, 0x02, 0x03, 0x01, 0x00, + 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x41, 0x00, 0x02, 0xd7, 0xdd, 0xbd, 0x0c, + 0x8e, 0x21, 0x20, 0xef, 0x9e, 0x4f, 0x1f, 0xf5, + 0x49, 0xf1, 0xae, 0x58, 0x9b, 0x94, 0x3a, 0x1f, + 0x70, 0x33, 0xf0, 0x9b, 0xbb, 0xe9, 0xc0, 0xf3, + 0x72, 0xcb, 0xde, 0xb6, 0x56, 0x72, 0xcc, 0x1c, + 0xf0, 0xd6, 0x5a, 0x2a, 0xbc, 0xa1, 0x7e, 0x23, + 0x83, 0xe9, 0xe7, 0xcf, 0x9e, 0xa5, 0xf9, 0xcc, + 0xc2, 0x61, 0xf4, 0xdb, 0x40, 0x93, 0x1d, 0x63, + 0x8a, 0x50, 0x4c, 0x11, 0x39, 0xb1, 0x91, 0xc1, + 0xe6, 0x9d, 0xd9, 0x1a, 0x62, 0x1b, 0xb8, 0xd3, + 0xd6, 0x9a, 0x6d, 0xb9, 0x8e, 0x15, 0x51 }; + + public static InputStream asInputStream() { + byte[] data = new byte[DATA.length]; + for (int i = 0; i < data.length; i ++) { + data[i] = (byte) DATA[i]; + } + return new ByteArrayInputStream(data); + } + + public static char[] getCertificatePassword() { + return "secret".toCharArray(); + } + + public static char[] getKeyStorePassword() { + return "secret".toCharArray(); + } + + private BogusKeyStore() { + // Unused + } + } +} diff --git a/src/test/java/io/netty/handler/codec/string/AbstractSocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketStringEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/string/AbstractSocketStringEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketStringEchoTest.java index c8be69048f..df1a1860c4 100644 --- a/src/test/java/io/netty/handler/codec/string/AbstractSocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/AbstractSocketStringEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.string; +package io.netty.testsuite.transport.socket; import static org.junit.Assert.*; @@ -37,16 +37,15 @@ import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelUpstreamHandler; import io.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import io.netty.handler.codec.frame.Delimiters; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; -import io.netty.util.TestUtil; +import io.netty.util.SocketAddresses; import io.netty.util.internal.ExecutorUtil; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -/** - */ public abstract class AbstractSocketStringEchoTest { static final Random random = new Random(); @@ -100,7 +99,7 @@ public abstract class AbstractSocketStringEchoTest { Channel sc = sb.bind(new InetSocketAddress(0)); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); - ChannelFuture ccf = cb.connect(new InetSocketAddress(TestUtil.getLocalHost(), port)); + ChannelFuture ccf = cb.connect(new InetSocketAddress(SocketAddresses.LOCALHOST, port)); assertTrue(ccf.awaitUninterruptibly().isSuccess()); Channel cc = ccf.getChannel(); diff --git a/src/test/java/io/netty/handler/codec/serialization/NioNioSocketCompatibleObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketCompatibleObjectStreamEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/serialization/NioNioSocketCompatibleObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketCompatibleObjectStreamEchoTest.java index 9725515f8d..9c096383d9 100644 --- a/src/test/java/io/netty/handler/codec/serialization/NioNioSocketCompatibleObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketCompatibleObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class NioNioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/frame/NioNioSocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketFixedLengthEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/frame/NioNioSocketFixedLengthEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketFixedLengthEchoTest.java index e9c41f03e3..75556cd940 100644 --- a/src/test/java/io/netty/handler/codec/frame/NioNioSocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketFixedLengthEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.frame; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class NioNioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/NioNioSocketObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/NioNioSocketObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketObjectStreamEchoTest.java index 596d59bc41..e966726f6d 100644 --- a/src/test/java/io/netty/handler/codec/serialization/NioNioSocketObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class NioNioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/string/NioNioSocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketStringEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/string/NioNioSocketStringEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketStringEchoTest.java index 492567e22f..d0ade4650e 100644 --- a/src/test/java/io/netty/handler/codec/string/NioNioSocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioNioSocketStringEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.string; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -/** - */ public class NioNioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/NioOioSocketCompatibleObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketCompatibleObjectStreamEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/serialization/NioOioSocketCompatibleObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketCompatibleObjectStreamEchoTest.java index b18110b3e1..6e7486b673 100644 --- a/src/test/java/io/netty/handler/codec/serialization/NioOioSocketCompatibleObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketCompatibleObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class NioOioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/frame/NioOioSocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketFixedLengthEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/frame/NioOioSocketFixedLengthEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketFixedLengthEchoTest.java index c5a0260bc5..b21b2c6701 100644 --- a/src/test/java/io/netty/handler/codec/frame/NioOioSocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketFixedLengthEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.frame; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class NioOioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/NioOioSocketObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/NioOioSocketObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketObjectStreamEchoTest.java index e693a10568..d847c6a68f 100644 --- a/src/test/java/io/netty/handler/codec/serialization/NioOioSocketObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class NioOioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/string/NioOioSocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketStringEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/string/NioOioSocketStringEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketStringEchoTest.java index 763e9956f4..659071386e 100644 --- a/src/test/java/io/netty/handler/codec/string/NioOioSocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/NioOioSocketStringEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.string; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class NioOioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/OioNioSocketCompatibleObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketCompatibleObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/OioNioSocketCompatibleObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketCompatibleObjectStreamEchoTest.java index 8d7e232aa5..d1b4af3825 100644 --- a/src/test/java/io/netty/handler/codec/serialization/OioNioSocketCompatibleObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketCompatibleObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; -/** - */ public class OioNioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/frame/OioNioSocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketFixedLengthEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/frame/OioNioSocketFixedLengthEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketFixedLengthEchoTest.java index 8dfee2731b..fc1810b549 100644 --- a/src/test/java/io/netty/handler/codec/frame/OioNioSocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketFixedLengthEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.frame; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; -/** - */ public class OioNioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/OioNioSocketObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketObjectStreamEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/serialization/OioNioSocketObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketObjectStreamEchoTest.java index c877cf3b6f..9e8689e406 100644 --- a/src/test/java/io/netty/handler/codec/serialization/OioNioSocketObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; diff --git a/src/test/java/io/netty/handler/codec/string/OioNioSocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketStringEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/string/OioNioSocketStringEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketStringEchoTest.java index a593dc7022..fbbc847240 100644 --- a/src/test/java/io/netty/handler/codec/string/OioNioSocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioNioSocketStringEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.string; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; -/** - */ public class OioNioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/OioOioSocketCompatibleObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketCompatibleObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/OioOioSocketCompatibleObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketCompatibleObjectStreamEchoTest.java index 98c47ab2ed..2b0203d52e 100644 --- a/src/test/java/io/netty/handler/codec/serialization/OioOioSocketCompatibleObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketCompatibleObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class OioOioSocketCompatibleObjectStreamEchoTest extends AbstractSocketCompatibleObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/frame/OioOioSocketFixedLengthEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketFixedLengthEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/frame/OioOioSocketFixedLengthEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketFixedLengthEchoTest.java index 77ba5de155..fc664d124e 100644 --- a/src/test/java/io/netty/handler/codec/frame/OioOioSocketFixedLengthEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketFixedLengthEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.frame; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class OioOioSocketFixedLengthEchoTest extends AbstractSocketFixedLengthEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/serialization/OioOioSocketObjectStreamEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketObjectStreamEchoTest.java similarity index 95% rename from src/test/java/io/netty/handler/codec/serialization/OioOioSocketObjectStreamEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketObjectStreamEchoTest.java index d3149e04d6..c6318ca98f 100644 --- a/src/test/java/io/netty/handler/codec/serialization/OioOioSocketObjectStreamEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketObjectStreamEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.serialization; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class OioOioSocketObjectStreamEchoTest extends AbstractSocketObjectStreamEchoTest { @Override diff --git a/src/test/java/io/netty/handler/codec/string/OioOioSocketStringEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketStringEchoTest.java similarity index 96% rename from src/test/java/io/netty/handler/codec/string/OioOioSocketStringEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketStringEchoTest.java index 74f5164302..50e785388c 100644 --- a/src/test/java/io/netty/handler/codec/string/OioOioSocketStringEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/OioOioSocketStringEchoTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.codec.string; +package io.netty.testsuite.transport.socket; import java.util.concurrent.Executor; @@ -21,8 +21,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; -/** - */ public class OioOioSocketStringEchoTest extends AbstractSocketStringEchoTest { @Override diff --git a/src/test/java/io/netty/channel/socket/NioClientSocketShutdownTimeTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioClientSocketShutdownTimeTest.java similarity index 93% rename from src/test/java/io/netty/channel/socket/NioClientSocketShutdownTimeTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioClientSocketShutdownTimeTest.java index 51ffc8236a..abf56948f6 100644 --- a/src/test/java/io/netty/channel/socket/NioClientSocketShutdownTimeTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioClientSocketShutdownTimeTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.nio; import static org.junit.Assert.*; @@ -22,16 +22,14 @@ import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; import java.util.concurrent.Executors; +import org.junit.Test; + import io.netty.bootstrap.ClientBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; -import io.netty.util.DummyHandler; -import io.netty.util.TestUtil; -import org.junit.Test; +import io.netty.testsuite.util.DummyHandler; +import io.netty.util.SocketAddresses; - -/** - */ public class NioClientSocketShutdownTimeTest { @Test @@ -52,7 +50,7 @@ public class NioClientSocketShutdownTimeTest { serverSocket.configureBlocking(false); ChannelFuture f = b.connect(new InetSocketAddress( - TestUtil.getLocalHost(), + SocketAddresses.LOCALHOST, serverSocket.socket().getLocalPort())); serverSocket.accept(); diff --git a/src/test/java/io/netty/channel/socket/NioServerSocketShutdownTimeTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioServerSocketShutdownTimeTest.java similarity index 96% rename from src/test/java/io/netty/channel/socket/NioServerSocketShutdownTimeTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioServerSocketShutdownTimeTest.java index 534fc0cb68..f67795d4b8 100644 --- a/src/test/java/io/netty/channel/socket/NioServerSocketShutdownTimeTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioServerSocketShutdownTimeTest.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.nio; import static org.junit.Assert.*; @@ -28,12 +28,9 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelStateEvent; import io.netty.channel.SimpleChannelUpstreamHandler; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; -import io.netty.util.TestUtil; +import io.netty.util.SocketAddresses; import org.junit.Test; - -/** - */ public class NioServerSocketShutdownTimeTest { @Test(timeout = 10000) @@ -57,7 +54,7 @@ public class NioServerSocketShutdownTimeTest { Socket socket = null; try { socket = new Socket( - TestUtil.getLocalHost(), + SocketAddresses.LOCALHOST, ((InetSocketAddress) channel.getLocalAddress()).getPort()); while (!handler.connected) { diff --git a/src/test/java/io/netty/bootstrap/NioSocketClientBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketClientBootstrapTest.java similarity index 90% rename from src/test/java/io/netty/bootstrap/NioSocketClientBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketClientBootstrapTest.java index a1a77dfd3d..56b80ad5ab 100644 --- a/src/test/java/io/netty/bootstrap/NioSocketClientBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketClientBootstrapTest.java @@ -13,12 +13,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketClientBootstrapTest; /** * A test for New I/O socket client bootstraps diff --git a/src/test/java/io/netty/bootstrap/NioSocketServerBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketServerBootstrapTest.java similarity index 90% rename from src/test/java/io/netty/bootstrap/NioSocketServerBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketServerBootstrapTest.java index f2e63968ff..7347ecdd5c 100644 --- a/src/test/java/io/netty/bootstrap/NioSocketServerBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/NioSocketServerBootstrapTest.java @@ -13,12 +13,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketServerBootstrapTest; /** * A test for New I/O socket server bootstraps diff --git a/src/test/java/io/netty/channel/socket/nio/UdpClient.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/UdpClient.java similarity index 95% rename from src/test/java/io/netty/channel/socket/nio/UdpClient.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/UdpClient.java index d891b20626..09c7847ce2 100644 --- a/src/test/java/io/netty/channel/socket/nio/UdpClient.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/UdpClient.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.nio; +package io.netty.testsuite.transport.socket.nio; import java.io.IOException; import java.net.DatagramPacket; @@ -65,11 +65,10 @@ public class UdpClient { * @param payload The payload of bytes to send * @return The datagram packet sent */ - public DatagramPacket send(final byte[] payload) throws IOException { + public void send(final byte[] payload) throws IOException { final DatagramPacket dp = new DatagramPacket(payload, payload.length, address, port); clientSocket.send(dp); - return dp; } /** diff --git a/src/test/java/io/netty/channel/socket/NioNioSocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketEchoTest.java similarity index 91% rename from src/test/java/io/netty/channel/socket/NioNioSocketEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketEchoTest.java index 44c234ae58..84d895fa76 100644 --- a/src/test/java/io/netty/channel/socket/NioNioSocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.nio.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketEchoTest; -/** - */ public class NioNioSocketEchoTest extends AbstractSocketEchoTest { @Override diff --git a/src/test/java/io/netty/handler/ssl/NioNioSocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketSslEchoTest.java similarity index 91% rename from src/test/java/io/netty/handler/ssl/NioNioSocketSslEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketSslEchoTest.java index bc1fca4c8e..6942f34c12 100644 --- a/src/test/java/io/netty/handler/ssl/NioNioSocketSslEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/nio/NioNioSocketSslEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.ssl; +package io.netty.testsuite.transport.socket.nio.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketSslEchoTest; -/** - */ public class NioNioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override diff --git a/src/test/java/io/netty/channel/socket/NioOioSocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketEchoTest.java similarity index 91% rename from src/test/java/io/netty/channel/socket/NioOioSocketEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketEchoTest.java index 10c3fee546..3ab69b2fbd 100644 --- a/src/test/java/io/netty/channel/socket/NioOioSocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.nio.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketEchoTest; -/** - */ public class NioOioSocketEchoTest extends AbstractSocketEchoTest { @Override diff --git a/src/test/java/io/netty/handler/ssl/NioOioSocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketSslEchoTest.java similarity index 91% rename from src/test/java/io/netty/handler/ssl/NioOioSocketSslEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketSslEchoTest.java index 6a9b9b2e10..909165ac58 100644 --- a/src/test/java/io/netty/handler/ssl/NioOioSocketSslEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/nio/oio/NioOioSocketSslEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.ssl; +package io.netty.testsuite.transport.socket.nio.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketSslEchoTest; -/** - */ public class NioOioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override diff --git a/src/test/java/io/netty/bootstrap/OioSocketClientBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketClientBootstrapTest.java similarity index 90% rename from src/test/java/io/netty/bootstrap/OioSocketClientBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketClientBootstrapTest.java index c6d864eacd..dc965f9b69 100644 --- a/src/test/java/io/netty/bootstrap/OioSocketClientBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketClientBootstrapTest.java @@ -13,12 +13,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketClientBootstrapTest; /** * A test for "Old" I/O socket client bootstraps diff --git a/src/test/java/io/netty/bootstrap/OioSocketServerBootstrapTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketServerBootstrapTest.java similarity index 90% rename from src/test/java/io/netty/bootstrap/OioSocketServerBootstrapTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketServerBootstrapTest.java index afd75d66b1..47da2f6660 100644 --- a/src/test/java/io/netty/bootstrap/OioSocketServerBootstrapTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/OioSocketServerBootstrapTest.java @@ -13,12 +13,13 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.bootstrap; +package io.netty.testsuite.transport.socket.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketServerBootstrapTest; /** * A socket server bootstrap test for "Old" I/O diff --git a/src/test/java/io/netty/channel/socket/OioNioSocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketEchoTest.java similarity index 91% rename from src/test/java/io/netty/channel/socket/OioNioSocketEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketEchoTest.java index b9e25256f9..09ba826cb0 100644 --- a/src/test/java/io/netty/channel/socket/OioNioSocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.oio.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketEchoTest; -/** - */ public class OioNioSocketEchoTest extends AbstractSocketEchoTest { @Override diff --git a/src/test/java/io/netty/handler/ssl/OioNioSocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketSslEchoTest.java similarity index 91% rename from src/test/java/io/netty/handler/ssl/OioNioSocketSslEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketSslEchoTest.java index 52a3abc3e5..65aa78ab65 100644 --- a/src/test/java/io/netty/handler/ssl/OioNioSocketSslEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/nio/OioNioSocketSslEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.ssl; +package io.netty.testsuite.transport.socket.oio.nio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketSslEchoTest; -/** - */ public class OioNioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override diff --git a/src/test/java/io/netty/channel/socket/OioOioSocketEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketEchoTest.java similarity index 91% rename from src/test/java/io/netty/channel/socket/OioOioSocketEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketEchoTest.java index c7d1a33e08..32cc3550e4 100644 --- a/src/test/java/io/netty/channel/socket/OioOioSocketEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket; +package io.netty.testsuite.transport.socket.oio.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketEchoTest; -/** - */ public class OioOioSocketEchoTest extends AbstractSocketEchoTest { @Override diff --git a/src/test/java/io/netty/handler/ssl/OioOioSocketSslEchoTest.java b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketSslEchoTest.java similarity index 91% rename from src/test/java/io/netty/handler/ssl/OioOioSocketSslEchoTest.java rename to testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketSslEchoTest.java index 97a26491c5..087352f0f0 100644 --- a/src/test/java/io/netty/handler/ssl/OioOioSocketSslEchoTest.java +++ b/testsuite/src/test/java/io/netty/testsuite/transport/socket/oio/oio/OioOioSocketSslEchoTest.java @@ -13,16 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.handler.ssl; +package io.netty.testsuite.transport.socket.oio.oio; import java.util.concurrent.Executor; import io.netty.channel.ChannelFactory; import io.netty.channel.socket.oio.OioClientSocketChannelFactory; import io.netty.channel.socket.oio.OioServerSocketChannelFactory; +import io.netty.testsuite.transport.socket.AbstractSocketSslEchoTest; -/** - */ public class OioOioSocketSslEchoTest extends AbstractSocketSslEchoTest { @Override diff --git a/src/test/java/io/netty/util/DummyHandler.java b/testsuite/src/test/java/io/netty/testsuite/util/DummyHandler.java similarity index 92% rename from src/test/java/io/netty/util/DummyHandler.java rename to testsuite/src/test/java/io/netty/testsuite/util/DummyHandler.java index ed2e7ed815..5ec679a904 100644 --- a/src/test/java/io/netty/util/DummyHandler.java +++ b/testsuite/src/test/java/io/netty/testsuite/util/DummyHandler.java @@ -13,25 +13,20 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.util; +package io.netty.testsuite.util; import io.netty.channel.ChannelDownstreamHandler; import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelUpstreamHandler; -/** - * A dummy handler for a testing purpose. - */ public class DummyHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { - @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { ctx.sendUpstream(e); } - @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { ctx.sendDownstream(e); diff --git a/transport-http/pom.xml b/transport-http/pom.xml new file mode 100644 index 0000000000..258604e89d --- /dev/null +++ b/transport-http/pom.xml @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-transport-http + jar + + Netty/Transport/HTTP + + + + ${project.groupId} + netty-codec-http + ${project.version} + + + + diff --git a/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelPipelineFactory.java b/transport-http/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/AcceptedServerChannelPipelineFactory.java rename to transport-http/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelPipelineFactory.java diff --git a/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatch.java b/transport-http/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatch.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatch.java rename to transport-http/src/main/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatch.java diff --git a/src/main/java/io/netty/channel/socket/http/DefaultTunnelIdGenerator.java b/transport-http/src/main/java/io/netty/channel/socket/http/DefaultTunnelIdGenerator.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/DefaultTunnelIdGenerator.java rename to transport-http/src/main/java/io/netty/channel/socket/http/DefaultTunnelIdGenerator.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java similarity index 98% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java index 2d37a5d067..7fa4a5f124 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannel.java @@ -36,7 +36,7 @@ import io.netty.channel.socket.SocketChannelConfig; * to change over the lifecycle of a tunnel, especially when an HTTP proxy is in * use. */ -class HttpTunnelAcceptedChannel extends AbstractChannel implements +final class HttpTunnelAcceptedChannel extends AbstractChannel implements SocketChannel, HttpTunnelAcceptedChannelReceiver { private final HttpTunnelAcceptedChannelConfig config; diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelConfig.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelConfig.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java index 94c99b77f5..8a4f1e7540 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelFactory.java @@ -27,4 +27,4 @@ interface HttpTunnelAcceptedChannelFactory { InetSocketAddress remoteAddress); String generateTunnelId(); -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelReceiver.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelReceiver.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelReceiver.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelReceiver.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSink.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSink.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSink.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSink.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelChannelConfig.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelChannelConfig.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java index da181b5787..5b1fe27814 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannel.java @@ -41,7 +41,7 @@ import io.netty.logging.InternalLoggerFactory; * this type are designed to emulate a normal TCP based socket channel as far as is feasible within the limitations * of the HTTP 1.1 protocol, and the usage patterns permitted by commonly used HTTP proxies and firewalls. */ -public class HttpTunnelClientChannel extends AbstractChannel implements +final class HttpTunnelClientChannel extends AbstractChannel implements SocketChannel { static final InternalLogger LOG = InternalLoggerFactory diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfig.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfig.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelFactory.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelFactory.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelSink.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelSink.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelSink.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientChannelSink.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientPollHandler.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientPollHandler.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientPollHandler.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientPollHandler.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java index 5697a18e0d..56448d7415 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientSendHandler.java @@ -44,7 +44,7 @@ class HttpTunnelClientSendHandler extends SimpleChannelHandler { private final HttpTunnelClientWorkerOwner tunnelChannel; - private String tunnelId = null; + private String tunnelId; private final AtomicBoolean disconnecting; diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java index 70b8f34742..e37195bf74 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelClientWorkerOwner.java @@ -61,4 +61,4 @@ interface HttpTunnelClientWorkerOwner { */ String getServerHostName(); -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java index e7d9231e55..81e81cb88f 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelMessageUtils.java @@ -40,7 +40,7 @@ import io.netty.handler.codec.http.HttpVersion; * Utility class for creating http requests for the operation of the full duplex * http tunnel, and verifying that received requests are of the correct types. */ -public class HttpTunnelMessageUtils { +final class HttpTunnelMessageUtils { private static final String HTTP_URL_PREFIX = "http://"; @@ -333,4 +333,8 @@ public class HttpTunnelMessageUtils { } return response; } + + private HttpTunnelMessageUtils() { + // Unused + } } diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java similarity index 98% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java index 9b66f4eb35..f9d01115a3 100644 --- a/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannel.java @@ -28,7 +28,7 @@ import io.netty.channel.socket.ServerSocketChannelConfig; /** */ -public class HttpTunnelServerChannel extends AbstractServerChannel implements +final class HttpTunnelServerChannel extends AbstractServerChannel implements ServerSocketChannel { private final ServerSocketChannel realChannel; diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelConfig.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelConfig.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactory.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactory.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelSink.java b/transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelSink.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelSink.java rename to transport-http/src/main/java/io/netty/channel/socket/http/HttpTunnelServerChannelSink.java diff --git a/src/main/java/io/netty/channel/socket/http/SaturationManager.java b/transport-http/src/main/java/io/netty/channel/socket/http/SaturationManager.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/SaturationManager.java rename to transport-http/src/main/java/io/netty/channel/socket/http/SaturationManager.java diff --git a/src/main/java/io/netty/channel/socket/http/SaturationStateChange.java b/transport-http/src/main/java/io/netty/channel/socket/http/SaturationStateChange.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/SaturationStateChange.java rename to transport-http/src/main/java/io/netty/channel/socket/http/SaturationStateChange.java diff --git a/src/main/java/io/netty/channel/socket/http/ServerMessageSwitch.java b/transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitch.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/ServerMessageSwitch.java rename to transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitch.java diff --git a/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java b/transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java rename to transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java index 75f15c290d..de42c6a528 100644 --- a/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchDownstreamInterface.java @@ -29,4 +29,4 @@ interface ServerMessageSwitchDownstreamInterface { void routeOutboundData(String tunnelId, ChannelBuffer data, ChannelFuture writeFuture); -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java b/transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java similarity index 99% rename from src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java rename to transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java index 83b750e9dd..7581fb1375 100644 --- a/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/ServerMessageSwitchUpstreamInterface.java @@ -50,4 +50,4 @@ interface ServerMessageSwitchUpstreamInterface { ALIVE, CLOSED } -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/socket/http/TunnelIdGenerator.java b/transport-http/src/main/java/io/netty/channel/socket/http/TunnelIdGenerator.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/TunnelIdGenerator.java rename to transport-http/src/main/java/io/netty/channel/socket/http/TunnelIdGenerator.java diff --git a/src/main/java/io/netty/channel/socket/http/TunnelWrappedServerChannelHandler.java b/transport-http/src/main/java/io/netty/channel/socket/http/TunnelWrappedServerChannelHandler.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/TunnelWrappedServerChannelHandler.java rename to transport-http/src/main/java/io/netty/channel/socket/http/TunnelWrappedServerChannelHandler.java diff --git a/src/main/java/io/netty/channel/socket/http/WriteFragmenter.java b/transport-http/src/main/java/io/netty/channel/socket/http/WriteFragmenter.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/WriteFragmenter.java rename to transport-http/src/main/java/io/netty/channel/socket/http/WriteFragmenter.java diff --git a/src/main/java/io/netty/channel/socket/http/WriteSplitter.java b/transport-http/src/main/java/io/netty/channel/socket/http/WriteSplitter.java similarity index 95% rename from src/main/java/io/netty/channel/socket/http/WriteSplitter.java rename to transport-http/src/main/java/io/netty/channel/socket/http/WriteSplitter.java index 7f5d2094cf..8d8ed5ab03 100644 --- a/src/main/java/io/netty/channel/socket/http/WriteSplitter.java +++ b/transport-http/src/main/java/io/netty/channel/socket/http/WriteSplitter.java @@ -25,7 +25,7 @@ import io.netty.buffer.ChannelBuffers; * Provides functionality to split a provided ChannelBuffer into multiple fragments which fit * under a specified size threshold. */ -public final class WriteSplitter { +final class WriteSplitter { public static List split(ChannelBuffer buffer, int splitThreshold) { @@ -50,4 +50,7 @@ public final class WriteSplitter { return fragmentList; } + private WriteSplitter() { + // Unused + } } diff --git a/src/main/java/io/netty/channel/socket/http/package-info.java b/transport-http/src/main/java/io/netty/channel/socket/http/package-info.java similarity index 100% rename from src/main/java/io/netty/channel/socket/http/package-info.java rename to transport-http/src/main/java/io/netty/channel/socket/http/package-info.java diff --git a/src/test/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatchTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatchTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatchTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/AcceptedServerChannelRequestDispatchTest.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeChannelConfig.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeChannelConfig.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeChannelConfig.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeChannelConfig.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeChannelSink.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeChannelSink.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeChannelSink.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeChannelSink.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeClientSocketChannelFactory.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeClientSocketChannelFactory.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeClientSocketChannelFactory.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeClientSocketChannelFactory.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannel.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannel.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeServerSocketChannel.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannel.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelConfig.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelConfig.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelConfig.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelConfig.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelFactory.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelFactory.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelFactory.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeServerSocketChannelFactory.java diff --git a/src/test/java/io/netty/channel/socket/http/FakeSocketChannel.java b/transport-http/src/test/java/io/netty/channel/socket/http/FakeSocketChannel.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/FakeSocketChannel.java rename to transport-http/src/test/java/io/netty/channel/socket/http/FakeSocketChannel.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSinkTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSinkTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSinkTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelAcceptedChannelSinkTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfigTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfigTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfigTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelConfigTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientChannelTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelClientPollHandlerTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientPollHandlerTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelClientPollHandlerTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientPollHandlerTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelClientSendHandlerTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientSendHandlerTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelClientSendHandlerTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelClientSendHandlerTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactoryTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactoryTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactoryTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelFactoryTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelSinkTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelSinkTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelSinkTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelSinkTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelServerChannelTest.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelSoakTester.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelSoakTester.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelSoakTester.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelSoakTester.java diff --git a/src/test/java/io/netty/channel/socket/http/HttpTunnelTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/HttpTunnelTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/HttpTunnelTest.java diff --git a/src/test/java/io/netty/channel/socket/http/MockChannelStateListener.java b/transport-http/src/test/java/io/netty/channel/socket/http/MockChannelStateListener.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/MockChannelStateListener.java rename to transport-http/src/test/java/io/netty/channel/socket/http/MockChannelStateListener.java diff --git a/src/test/java/io/netty/channel/socket/http/NettyTestUtils.java b/transport-http/src/test/java/io/netty/channel/socket/http/NettyTestUtils.java similarity index 99% rename from src/test/java/io/netty/channel/socket/http/NettyTestUtils.java rename to transport-http/src/test/java/io/netty/channel/socket/http/NettyTestUtils.java index 3e2b326139..58ada19ecb 100644 --- a/src/test/java/io/netty/channel/socket/http/NettyTestUtils.java +++ b/transport-http/src/test/java/io/netty/channel/socket/http/NettyTestUtils.java @@ -84,15 +84,12 @@ public class NettyTestUtils { return false; } - int position = 0; while (expected.readable()) { byte expectedByte = expected.readByte(); byte actualByte = actual.readByte(); if (expectedByte != actualByte) { return false; } - - position ++; } return true; diff --git a/src/test/java/io/netty/channel/socket/http/NettyTestUtilsTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/NettyTestUtilsTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/NettyTestUtilsTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/NettyTestUtilsTest.java diff --git a/src/test/java/io/netty/channel/socket/http/NullChannelHandler.java b/transport-http/src/test/java/io/netty/channel/socket/http/NullChannelHandler.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/NullChannelHandler.java rename to transport-http/src/test/java/io/netty/channel/socket/http/NullChannelHandler.java diff --git a/src/test/java/io/netty/channel/socket/http/SaturationManagerTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/SaturationManagerTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/SaturationManagerTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/SaturationManagerTest.java diff --git a/src/test/java/io/netty/channel/socket/http/ServerMessageSwitchTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/ServerMessageSwitchTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/ServerMessageSwitchTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/ServerMessageSwitchTest.java diff --git a/src/test/java/io/netty/channel/socket/http/UpstreamEventCatcher.java b/transport-http/src/test/java/io/netty/channel/socket/http/UpstreamEventCatcher.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/UpstreamEventCatcher.java rename to transport-http/src/test/java/io/netty/channel/socket/http/UpstreamEventCatcher.java diff --git a/src/test/java/io/netty/channel/socket/http/WriteFragmenterTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/WriteFragmenterTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/WriteFragmenterTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/WriteFragmenterTest.java diff --git a/src/test/java/io/netty/channel/socket/http/WriteSplitterTest.java b/transport-http/src/test/java/io/netty/channel/socket/http/WriteSplitterTest.java similarity index 100% rename from src/test/java/io/netty/channel/socket/http/WriteSplitterTest.java rename to transport-http/src/test/java/io/netty/channel/socket/http/WriteSplitterTest.java diff --git a/transport-rxtx/pom.xml b/transport-rxtx/pom.xml new file mode 100644 index 0000000000..ca39dd2e2c --- /dev/null +++ b/transport-rxtx/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-transport-rxtx + jar + + Netty/Transport/RXTX + + + + ${project.groupId} + netty-transport + ${project.version} + + + org.rxtx + rxtx + + + + diff --git a/src/main/java/io/netty/channel/rxtx/RXTXChannel.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannel.java similarity index 80% rename from src/main/java/io/netty/channel/rxtx/RXTXChannel.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannel.java index 92d50519be..51611aa442 100644 --- a/src/main/java/io/netty/channel/rxtx/RXTXChannel.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannel.java @@ -29,26 +29,26 @@ import io.netty.channel.ChannelSink; /** * A channel to a serial device using the RXTX library. */ -public class RXTXChannel extends AbstractChannel { +public class RxtxChannel extends AbstractChannel { - RXTXChannel(final Channel parent, final ChannelFactory factory, final ChannelPipeline pipeline, - final ChannelSink sink) { + RxtxChannel(final Channel parent, final ChannelFactory factory, final ChannelPipeline pipeline, + final ChannelSink sink) { super(parent, factory, pipeline, sink); } @Override public ChannelConfig getConfig() { - return ((RXTXChannelSink) getPipeline().getSink()).getConfig(); + return ((RxtxChannelSink) getPipeline().getSink()).getConfig(); } @Override public boolean isBound() { - return ((RXTXChannelSink) getPipeline().getSink()).isBound(); + return ((RxtxChannelSink) getPipeline().getSink()).isBound(); } @Override public boolean isConnected() { - return ((RXTXChannelSink) getPipeline().getSink()).isConnected(); + return ((RxtxChannelSink) getPipeline().getSink()).isConnected(); } @Override @@ -58,7 +58,7 @@ public class RXTXChannel extends AbstractChannel { @Override public SocketAddress getRemoteAddress() { - return ((RXTXChannelSink) getPipeline().getSink()).getRemoteAddress(); + return ((RxtxChannelSink) getPipeline().getSink()).getRemoteAddress(); } @Override diff --git a/src/main/java/io/netty/channel/rxtx/RXTXChannelConfig.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java similarity index 92% rename from src/main/java/io/netty/channel/rxtx/RXTXChannelConfig.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java index 50537cad84..cf623db903 100644 --- a/src/main/java/io/netty/channel/rxtx/RXTXChannelConfig.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelConfig.java @@ -23,7 +23,7 @@ import io.netty.util.internal.ConversionUtil; /** * A configuration class for RXTX device connections. */ -public class RXTXChannelConfig extends DefaultChannelConfig { +public class RxtxChannelConfig extends DefaultChannelConfig { public enum Stopbits { @@ -108,21 +108,21 @@ public class RXTXChannelConfig extends DefaultChannelConfig { private int baudrate = 115200; - private boolean dtr = false; + private boolean dtr; - private boolean rts = false; + private boolean rts; - private Stopbits stopbits = RXTXChannelConfig.Stopbits.STOPBITS_1; + private Stopbits stopbits = RxtxChannelConfig.Stopbits.STOPBITS_1; - private Databits databits = RXTXChannelConfig.Databits.DATABITS_8; + private Databits databits = RxtxChannelConfig.Databits.DATABITS_8; - private Paritybit paritybit = RXTXChannelConfig.Paritybit.NONE; + private Paritybit paritybit = RxtxChannelConfig.Paritybit.NONE; - public RXTXChannelConfig() { + public RxtxChannelConfig() { // work with defaults ... } - public RXTXChannelConfig(final int baudrate, final boolean dtr, final boolean rts, final Stopbits stopbits, + public RxtxChannelConfig(final int baudrate, final boolean dtr, final boolean rts, final Stopbits stopbits, final Databits databits, final Paritybit paritybit) { this.baudrate = baudrate; this.dtr = dtr; diff --git a/src/main/java/io/netty/channel/rxtx/RXTXChannelFactory.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelFactory.java similarity index 83% rename from src/main/java/io/netty/channel/rxtx/RXTXChannelFactory.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelFactory.java index fced2f2c95..095b708c69 100644 --- a/src/main/java/io/netty/channel/rxtx/RXTXChannelFactory.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelFactory.java @@ -27,22 +27,22 @@ import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.internal.ExecutorUtil; /** - * A {@link ChannelFactory} for creating {@link RXTXChannel} instances. + * A {@link ChannelFactory} for creating {@link RxtxChannel} instances. */ -public class RXTXChannelFactory implements ChannelFactory { +public class RxtxChannelFactory implements ChannelFactory { private final ChannelGroup channels = new DefaultChannelGroup("RXTXChannelFactory-ChannelGroup"); private final ExecutorService executor; - public RXTXChannelFactory(ExecutorService executor) { + public RxtxChannelFactory(ExecutorService executor) { this.executor = executor; } @Override public Channel newChannel(final ChannelPipeline pipeline) { - RXTXChannelSink sink = new RXTXChannelSink(executor); - RXTXChannel channel = new RXTXChannel(null, this, pipeline, sink); + RxtxChannelSink sink = new RxtxChannelSink(executor); + RxtxChannel channel = new RxtxChannel(null, this, pipeline, sink); sink.setChannel(channel); channels.add(channel); return channel; diff --git a/src/main/java/io/netty/channel/rxtx/RXTXChannelSink.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelSink.java similarity index 92% rename from src/main/java/io/netty/channel/rxtx/RXTXChannelSink.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelSink.java index 65effa8855..fd1c34c0a0 100644 --- a/src/main/java/io/netty/channel/rxtx/RXTXChannelSink.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxChannelSink.java @@ -48,17 +48,17 @@ import io.netty.channel.UpstreamMessageEvent; /** * A {@link ChannelSink} implementation of the RXTX support for Netty. */ -public class RXTXChannelSink extends AbstractChannelSink { +public class RxtxChannelSink extends AbstractChannelSink { private static class WriteRunnable implements Runnable { private final DefaultChannelFuture future; - private final RXTXChannelSink channelSink; + private final RxtxChannelSink channelSink; private final ChannelBuffer message; - public WriteRunnable(final DefaultChannelFuture future, final RXTXChannelSink channelSink, + public WriteRunnable(final DefaultChannelFuture future, final RxtxChannelSink channelSink, final ChannelBuffer message) { this.future = future; this.channelSink = channelSink; @@ -83,9 +83,9 @@ public class RXTXChannelSink extends AbstractChannelSink { private final DefaultChannelFuture channelFuture; - private final RXTXChannelSink channelSink; + private final RxtxChannelSink channelSink; - ConnectRunnable(final DefaultChannelFuture channelFuture, final RXTXChannelSink channelSink) { + ConnectRunnable(final DefaultChannelFuture channelFuture, final RxtxChannelSink channelSink) { this.channelFuture = channelFuture; this.channelSink = channelSink; } @@ -145,9 +145,9 @@ public class RXTXChannelSink extends AbstractChannelSink { private final DefaultChannelFuture channelFuture; - private final RXTXChannelSink channelSink; + private final RxtxChannelSink channelSink; - public DisconnectRunnable(final DefaultChannelFuture channelFuture, final RXTXChannelSink channelSink) { + public DisconnectRunnable(final DefaultChannelFuture channelFuture, final RxtxChannelSink channelSink) { this.channelFuture = channelFuture; this.channelSink = channelSink; } @@ -203,20 +203,20 @@ public class RXTXChannelSink extends AbstractChannelSink { private final Executor executor; - final RXTXChannelConfig config; + final RxtxChannelConfig config; - RXTXChannel channel; + RxtxChannel channel; - public RXTXChannelSink(final Executor executor) { + public RxtxChannelSink(final Executor executor) { this.executor = executor; - config = new RXTXChannelConfig(); + config = new RxtxChannelConfig(); } public boolean isConnected() { return inputStream != null && outputStream != null; } - public RXTXDeviceAddress getRemoteAddress() { + public RxtxDeviceAddress getRemoteAddress() { return remoteAddress; } @@ -228,15 +228,15 @@ public class RXTXChannelSink extends AbstractChannelSink { return config; } - public void setChannel(final RXTXChannel channel) { + public void setChannel(final RxtxChannel channel) { this.channel = channel; } private static class RXTXSerialPortEventListener implements SerialPortEventListener { - private final RXTXChannelSink channelSink; + private final RxtxChannelSink channelSink; - public RXTXSerialPortEventListener(final RXTXChannelSink channelSink) { + public RXTXSerialPortEventListener(final RxtxChannelSink channelSink) { this.channelSink = channelSink; } @@ -268,7 +268,7 @@ public class RXTXChannelSink extends AbstractChannelSink { } } - RXTXDeviceAddress remoteAddress; + RxtxDeviceAddress remoteAddress; BufferedOutputStream outputStream; @@ -276,7 +276,7 @@ public class RXTXChannelSink extends AbstractChannelSink { SerialPort serialPort; - volatile boolean closed = false; + volatile boolean closed; @Override public void eventSunk(final ChannelPipeline pipeline, final ChannelEvent e) throws Exception { @@ -302,7 +302,7 @@ public class RXTXChannelSink extends AbstractChannelSink { case CONNECTED: if (value != null) { - remoteAddress = (RXTXDeviceAddress) value; + remoteAddress = (RxtxDeviceAddress) value; executor.execute(new ConnectRunnable((DefaultChannelFuture) future, this)); } else { executor.execute(new DisconnectRunnable((DefaultChannelFuture) future, this)); diff --git a/src/main/java/io/netty/channel/rxtx/RXTXDeviceAddress.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxDeviceAddress.java similarity index 91% rename from src/main/java/io/netty/channel/rxtx/RXTXDeviceAddress.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxDeviceAddress.java index 1041d37543..d018823891 100644 --- a/src/main/java/io/netty/channel/rxtx/RXTXDeviceAddress.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/RxtxDeviceAddress.java @@ -21,7 +21,7 @@ import java.net.SocketAddress; * A {@link SocketAddress} subclass to wrap the serial port address of a RXTX * device (e.g. COM1, /dev/ttyUSB0). */ -public class RXTXDeviceAddress extends SocketAddress { +public class RxtxDeviceAddress extends SocketAddress { private static final long serialVersionUID = -2907820090993709523L; @@ -31,7 +31,7 @@ public class RXTXDeviceAddress extends SocketAddress { * * @param deviceAddress the address of the device (e.g. COM1, /dev/ttyUSB0, ...) */ - public RXTXDeviceAddress(String deviceAddress) { + public RxtxDeviceAddress(String deviceAddress) { this.deviceAddress = deviceAddress; } diff --git a/src/main/java/io/netty/container/spring/package-info.java b/transport-rxtx/src/main/java/io/netty/channel/rxtx/package-info.java similarity index 82% rename from src/main/java/io/netty/container/spring/package-info.java rename to transport-rxtx/src/main/java/io/netty/channel/rxtx/package-info.java index 42a55f3152..90719423ef 100644 --- a/src/main/java/io/netty/container/spring/package-info.java +++ b/transport-rxtx/src/main/java/io/netty/channel/rxtx/package-info.java @@ -15,8 +15,6 @@ */ /** - * Spring framework integration. - * - * @apiviz.exclude + * A serial and parallel port communication transport based on RXTX. */ -package io.netty.container.spring; +package io.netty.channel.rxtx; diff --git a/transport-sctp/pom.xml b/transport-sctp/pom.xml new file mode 100644 index 0000000000..c14941d722 --- /dev/null +++ b/transport-sctp/pom.xml @@ -0,0 +1,39 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-transport-sctp + jar + + Netty/Transport/SCTP + + + + ${project.groupId} + netty-transport + ${project.version} + + + diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/AbstractNotificationHandler.java b/transport-sctp/src/main/java/com/sun/nio/sctp/AbstractNotificationHandler.java new file mode 100644 index 0000000000..bade95b264 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/AbstractNotificationHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public class AbstractNotificationHandler implements NotificationHandler { + static { + UnsupportedOperatingSystemException.raise(); + } + + public HandlerResult handleNotification(AssociationChangeNotification notification, Object o) { + return null; + } + + public HandlerResult handleNotification(Notification notification, Object o) { + return null; + } + + public HandlerResult handleNotification(PeerAddressChangeNotification notification, Object o) { + return null; + } + + public HandlerResult handleNotification(SendFailedNotification notification, Object o) { + return null; + } + + public HandlerResult handleNotification(ShutdownNotification notification, Object o) { + return null; + } +} diff --git a/src/main/java/io/netty/container/osgi/package-info.java b/transport-sctp/src/main/java/com/sun/nio/sctp/Association.java similarity index 83% rename from src/main/java/io/netty/container/osgi/package-info.java rename to transport-sctp/src/main/java/com/sun/nio/sctp/Association.java index f146965fa3..e190295f5e 100644 --- a/src/main/java/io/netty/container/osgi/package-info.java +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/Association.java @@ -13,10 +13,10 @@ * License for the specific language governing permissions and limitations * under the License. */ +package com.sun.nio.sctp; -/** - * OSGi framework integration. - * - * @apiviz.exclude - */ -package io.netty.container.osgi; +public class Association { + static { + UnsupportedOperatingSystemException.raise(); + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/AssociationChangeNotification.java b/transport-sctp/src/main/java/com/sun/nio/sctp/AssociationChangeNotification.java new file mode 100644 index 0000000000..8b8098c851 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/AssociationChangeNotification.java @@ -0,0 +1,22 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public abstract class AssociationChangeNotification implements Notification { + static { + UnsupportedOperatingSystemException.raise(); + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/HandlerResult.java b/transport-sctp/src/main/java/com/sun/nio/sctp/HandlerResult.java new file mode 100644 index 0000000000..f75088140b --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/HandlerResult.java @@ -0,0 +1,25 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +/** + * TODO Document me. + * + * @author Trustin Lee + */ +public enum HandlerResult { + CONTINUE, RETURN; +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/MessageInfo.java b/transport-sctp/src/main/java/com/sun/nio/sctp/MessageInfo.java new file mode 100644 index 0000000000..bab8487f3f --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/MessageInfo.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +import java.net.SocketAddress; + +public abstract class MessageInfo { + static { + UnsupportedOperatingSystemException.raise(); + } + + public static MessageInfo createOutgoing(Association association, SocketAddress address, int streamNumber) { + return null; + } + + public abstract SocketAddress address(); + public abstract int streamNumber(); + public abstract MessageInfo streamNumber(int streamNumber); + public abstract int payloadProtocolID(); + public abstract MessageInfo payloadProtocolID(int ppid); + public abstract boolean isComplete(); + +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/Notification.java b/transport-sctp/src/main/java/com/sun/nio/sctp/Notification.java new file mode 100644 index 0000000000..32f1a809c9 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/Notification.java @@ -0,0 +1,20 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public interface Notification { + Association association(); +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/NotificationHandler.java b/transport-sctp/src/main/java/com/sun/nio/sctp/NotificationHandler.java new file mode 100644 index 0000000000..1b86c0c57e --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/NotificationHandler.java @@ -0,0 +1,19 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public interface NotificationHandler { +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/PeerAddressChangeNotification.java b/transport-sctp/src/main/java/com/sun/nio/sctp/PeerAddressChangeNotification.java new file mode 100644 index 0000000000..7c61551edb --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/PeerAddressChangeNotification.java @@ -0,0 +1,22 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public abstract class PeerAddressChangeNotification implements Notification { + static { + UnsupportedOperatingSystemException.raise(); + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/SctpChannel.java b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpChannel.java new file mode 100644 index 0000000000..287c40041b --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpChannel.java @@ -0,0 +1,50 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +import java.io.IOException; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; +import java.util.Set; + +public abstract class SctpChannel extends AbstractSelectableChannel { + static { + UnsupportedOperatingSystemException.raise(); + } + + public static SctpChannel open() throws IOException { + return null; + } + + protected SctpChannel(SelectorProvider provider) { + super(provider); + } + + public abstract T getOption(SctpSocketOption name) throws IOException; + public abstract SctpChannel setOption(SctpSocketOption name, T value) throws IOException; + + public abstract Set getAllLocalAddresses() throws IOException; + public abstract Set getRemoteAddresses() throws IOException; + + public abstract Association association() throws IOException; + public abstract SctpChannel bind(SocketAddress local) throws IOException; + public abstract boolean connect(SocketAddress remote) throws IOException; + public abstract boolean finishConnect() throws IOException; + public abstract MessageInfo receive(ByteBuffer dst, T attachment, NotificationHandler handler) throws IOException; + public abstract int send(ByteBuffer src, MessageInfo messageInfo) throws IOException; +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/SctpServerChannel.java b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpServerChannel.java new file mode 100644 index 0000000000..772a768825 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpServerChannel.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +import java.io.IOException; +import java.net.SocketAddress; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.SelectorProvider; +import java.util.Set; + +public abstract class SctpServerChannel extends AbstractSelectableChannel { + static { + UnsupportedOperatingSystemException.raise(); + } + + public static SctpServerChannel open() throws IOException { + return null; + } + + protected SctpServerChannel(SelectorProvider provider) { + super(provider); + } + + public abstract T getOption(SctpSocketOption name) throws IOException; + public abstract SctpChannel setOption(SctpSocketOption name, T value) throws IOException; + + public abstract Set getAllLocalAddresses() throws IOException; + + public abstract SctpServerChannel bind(SocketAddress local) throws IOException; + public abstract SctpServerChannel bind(SocketAddress local, int backlog) throws IOException; + public abstract SctpChannel accept() throws IOException; +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/SctpSocketOption.java b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpSocketOption.java new file mode 100644 index 0000000000..66ca504ceb --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpSocketOption.java @@ -0,0 +1,21 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public interface SctpSocketOption { + String name(); + Class type(); +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/SctpStandardSocketOptions.java b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpStandardSocketOptions.java new file mode 100644 index 0000000000..f5418a9b31 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/SctpStandardSocketOptions.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +import java.net.SocketAddress; + +public class SctpStandardSocketOptions { + static { + UnsupportedOperatingSystemException.raise(); + } + + public static final SctpSocketOption SCTP_DISABLE_FRAGMENTS = null; + public static final SctpSocketOption SCTP_EXPLICIT_COMPLETE = null; + public static final SctpSocketOption SCTP_FRAGMENT_INTERLEAVE = null; + public static final SctpSocketOption SCTP_INIT_MAXSTREAMS = null; + public static final SctpSocketOption SCTP_NODELAY = null; + public static final SctpSocketOption SCTP_PRIMARY_ADDR = null; + public static final SctpSocketOption SCTP_SET_PEER_PRIMARY_ADDR = null; + public static final SctpSocketOption SO_LINGER = null; + public static final SctpSocketOption SO_RCVBUF = null; + public static final SctpSocketOption SO_SNDBUF = null; + + public static class InitMaxStreams { + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/SendFailedNotification.java b/transport-sctp/src/main/java/com/sun/nio/sctp/SendFailedNotification.java new file mode 100644 index 0000000000..47bbe89ad9 --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/SendFailedNotification.java @@ -0,0 +1,22 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public abstract class SendFailedNotification implements Notification { + static { + UnsupportedOperatingSystemException.raise(); + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/ShutdownNotification.java b/transport-sctp/src/main/java/com/sun/nio/sctp/ShutdownNotification.java new file mode 100644 index 0000000000..d0f408c2da --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/ShutdownNotification.java @@ -0,0 +1,22 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public abstract class ShutdownNotification implements Notification { + static { + UnsupportedOperatingSystemException.raise(); + } +} diff --git a/transport-sctp/src/main/java/com/sun/nio/sctp/UnsupportedOperatingSystemException.java b/transport-sctp/src/main/java/com/sun/nio/sctp/UnsupportedOperatingSystemException.java new file mode 100644 index 0000000000..ad990c757f --- /dev/null +++ b/transport-sctp/src/main/java/com/sun/nio/sctp/UnsupportedOperatingSystemException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.sun.nio.sctp; + +public class UnsupportedOperatingSystemException extends RuntimeException { + public static void raise() { + throw new UnsupportedOperatingSystemException(); + } + + public UnsupportedOperatingSystemException() { + super(); + } + + public UnsupportedOperatingSystemException(String message) { + super(message); + } + + public UnsupportedOperatingSystemException(String message, Throwable cause) { + super(message, cause); + } + + public UnsupportedOperatingSystemException(Throwable cause) { + super(cause); + } +} diff --git a/transport-sctp/src/main/java/io/netty/channel/sctp/AbstractWriteRequestQueue.java b/transport-sctp/src/main/java/io/netty/channel/sctp/AbstractWriteRequestQueue.java new file mode 100644 index 0000000000..b2b6ce436d --- /dev/null +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/AbstractWriteRequestQueue.java @@ -0,0 +1,149 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.channel.sctp; + +import java.util.Collection; +import java.util.Iterator; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import io.netty.channel.MessageEvent; +import io.netty.util.internal.QueueFactory; + +abstract class AbstractWriteRequestQueue implements BlockingQueue { + + protected final BlockingQueue queue; + + public AbstractWriteRequestQueue() { + this.queue = QueueFactory.createQueue(MessageEvent.class); + } + + @Override + public MessageEvent remove() { + return queue.remove(); + } + + @Override + public MessageEvent element() { + return queue.element(); + } + + @Override + public MessageEvent peek() { + return queue.peek(); + } + + @Override + public int size() { + return queue.size(); + } + + @Override + public boolean isEmpty() { + return queue.isEmpty(); + } + + @Override + public Iterator iterator() { + return queue.iterator(); + } + + @Override + public Object[] toArray() { + return queue.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return queue.toArray(a); + } + + @Override + public boolean containsAll(Collection c) { + return queue.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return queue.addAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return queue.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return queue.retainAll(c); + } + + @Override + public void clear() { + queue.clear(); + } + + @Override + public boolean add(MessageEvent e) { + return queue.add(e); + } + + @Override + public void put(MessageEvent e) throws InterruptedException { + queue.put(e); + } + + @Override + public boolean offer(MessageEvent e, long timeout, TimeUnit unit) throws InterruptedException { + return queue.offer(e, timeout, unit); + } + + @Override + public MessageEvent take() throws InterruptedException { + return queue.take(); + } + + @Override + public MessageEvent poll(long timeout, TimeUnit unit) throws InterruptedException { + return queue.poll(timeout, unit); + } + + @Override + public int remainingCapacity() { + return queue.remainingCapacity(); + } + + @Override + public boolean remove(Object o) { + return queue.remove(o); + } + + @Override + public boolean contains(Object o) { + return queue.contains(o); + } + + @Override + public int drainTo(Collection c) { + return queue.drainTo(c); + } + + @Override + public int drainTo(Collection c, int maxElements) { + return queue.drainTo(c, maxElements); + } + +} diff --git a/src/main/java/io/netty/channel/socket/sctp/DefaultNioSctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultNioSctpChannelConfig.java similarity index 99% rename from src/main/java/io/netty/channel/socket/sctp/DefaultNioSctpChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/DefaultNioSctpChannelConfig.java index 46c83e7155..7fc830413f 100644 --- a/src/main/java/io/netty/channel/socket/sctp/DefaultNioSctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultNioSctpChannelConfig.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.SctpChannel; import java.util.Map; diff --git a/src/main/java/io/netty/channel/socket/sctp/DefaultSctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java similarity index 99% rename from src/main/java/io/netty/channel/socket/sctp/DefaultSctpChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java index a5bff95e82..25d667951d 100644 --- a/src/main/java/io/netty/channel/socket/sctp/DefaultSctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpChannelConfig.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.SctpChannel; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; diff --git a/src/main/java/io/netty/channel/socket/sctp/DefaultSctpServerChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java similarity index 98% rename from src/main/java/io/netty/channel/socket/sctp/DefaultSctpServerChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java index 04e876a2a4..b311b31c0b 100644 --- a/src/main/java/io/netty/channel/socket/sctp/DefaultSctpServerChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/DefaultSctpServerChannelConfig.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; diff --git a/src/main/java/io/netty/channel/socket/sctp/NioSctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/NioSctpChannelConfig.java similarity index 95% rename from src/main/java/io/netty/channel/socket/sctp/NioSctpChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/NioSctpChannelConfig.java index cab189a377..69f8fe791d 100644 --- a/src/main/java/io/netty/channel/socket/sctp/NioSctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/NioSctpChannelConfig.java @@ -13,19 +13,19 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.channel.ReceiveBufferSizePredictor; import io.netty.channel.ReceiveBufferSizePredictorFactory; import io.netty.channel.socket.SocketChannelConfig; /** - * A {@link io.netty.channel.socket.sctp.SctpChannelConfig} for a NIO SCTP/IP {@link io.netty.channel.socket.sctp.SctpChannel}. + * A {@link io.netty.channel.sctp.SctpChannelConfig} for a NIO SCTP/IP {@link io.netty.channel.sctp.SctpChannel}. * *

      Available options

      * * In addition to the options provided by {@link io.netty.channel.ChannelConfig} and - * {@link io.netty.channel.socket.sctp.SctpChannelConfig}, {@link io.netty.channel.socket.sctp.NioSctpChannelConfig} allows the + * {@link io.netty.channel.sctp.SctpChannelConfig}, {@link io.netty.channel.sctp.NioSctpChannelConfig} allows the * following options in the option map: * * diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpAcceptedChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpAcceptedChannel.java similarity index 97% rename from src/main/java/io/netty/channel/socket/sctp/SctpAcceptedChannel.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpAcceptedChannel.java index 9fc99d9ac8..7996280614 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpAcceptedChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpAcceptedChannel.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.SctpChannel; import io.netty.channel.Channel; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannel.java similarity index 97% rename from src/main/java/io/netty/channel/socket/sctp/SctpChannel.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannel.java index a3f4c2cb28..df0b9392ac 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannel.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.Association; import io.netty.channel.Channel; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java similarity index 95% rename from src/main/java/io/netty/channel/socket/sctp/SctpChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java index c0c994d581..bf67ec3ac2 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelConfig.java @@ -13,18 +13,18 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; import io.netty.channel.ChannelConfig; /** - * A {@link io.netty.channel.ChannelConfig} for a {@link io.netty.channel.socket.sctp.SctpChannel}. + * A {@link io.netty.channel.ChannelConfig} for a {@link io.netty.channel.sctp.SctpChannel}. *

      *

      Available options

      *

      * In addition to the options provided by {@link io.netty.channel.ChannelConfig}, - * {@link io.netty.channel.socket.sctp.SctpChannelConfig} allows the following options in the option map: + * {@link io.netty.channel.sctp.SctpChannelConfig} allows the following options in the option map: *

      *

      * diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpChannelImpl.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelImpl.java similarity index 91% rename from src/main/java/io/netty/channel/socket/sctp/SctpChannelImpl.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelImpl.java index b882c02655..a73e42c4a6 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpChannelImpl.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpChannelImpl.java @@ -13,22 +13,33 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import com.sun.nio.sctp.Association; -import io.netty.buffer.ChannelBuffer; -import io.netty.channel.*; -import io.netty.channel.socket.sctp.SctpSendBufferPool.SendBuffer; -import io.netty.util.internal.ThreadLocalBoolean; +import static io.netty.channel.Channels.*; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.*; -import java.util.concurrent.LinkedTransferQueue; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Queue; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import static io.netty.channel.Channels.fireChannelInterestChanged; +import com.sun.nio.sctp.Association; + +import io.netty.buffer.ChannelBuffer; +import io.netty.channel.AbstractChannel; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelSink; +import io.netty.channel.MessageEvent; +import io.netty.channel.sctp.SctpSendBufferPool.SendBuffer; +import io.netty.util.internal.ThreadLocalBoolean; /** */ @@ -103,7 +114,7 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel { try { final Set allLocalAddresses = channel.getAllLocalAddresses(); final Set addresses = new HashSet(allLocalAddresses.size()); - for(SocketAddress socketAddress: allLocalAddresses) { + for (SocketAddress socketAddress: allLocalAddresses) { addresses.add((InetSocketAddress) socketAddress); } return addresses; @@ -133,7 +144,7 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel { try { final Set allLocalAddresses = channel.getRemoteAddresses(); final Set addresses = new HashSet(allLocalAddresses.size()); - for(SocketAddress socketAddress: allLocalAddresses) { + for (SocketAddress socketAddress: allLocalAddresses) { addresses.add((InetSocketAddress) socketAddress); } return addresses; @@ -230,7 +241,7 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel { } } - private final class WriteRequestQueue extends LinkedTransferQueue { + private final class WriteRequestQueue extends AbstractWriteRequestQueue { private static final long serialVersionUID = -246694024103520626L; @@ -242,7 +253,7 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel { @Override public boolean offer(MessageEvent e) { - boolean success = super.offer(e); + boolean success = queue.offer(e); assert success; int messageSize = getMessageSize(e); @@ -264,7 +275,7 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel { @Override public MessageEvent poll() { - MessageEvent e = super.poll(); + MessageEvent e = queue.poll(); if (e != null) { int messageSize = getMessageSize(e); int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize); diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpClientChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientChannel.java similarity index 89% rename from src/main/java/io/netty/channel/socket/sctp/SctpClientChannel.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientChannel.java index e58627c48a..e875e67bb3 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpClientChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientChannel.java @@ -13,16 +13,21 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import com.sun.nio.sctp.SctpChannel; -import io.netty.channel.*; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; +import static io.netty.channel.Channels.*; import java.io.IOException; -import static io.netty.channel.Channels.fireChannelOpen; +import com.sun.nio.sctp.SctpChannel; + +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelSink; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; /** */ diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpClientPipelineSink.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientPipelineSink.java similarity index 96% rename from src/main/java/io/netty/channel/socket/sctp/SctpClientPipelineSink.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientPipelineSink.java index a6654c451a..cdd483beb2 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpClientPipelineSink.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientPipelineSink.java @@ -13,12 +13,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import io.netty.channel.*; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.internal.DeadLockProofWorker; +import static io.netty.channel.Channels.*; import java.io.IOException; import java.net.ConnectException; @@ -31,11 +28,22 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import static io.netty.channel.Channels.*; +import io.netty.channel.AbstractChannelSink; +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelState; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.MessageEvent; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.internal.DeadLockProofWorker; +import io.netty.util.internal.QueueFactory; /** */ @@ -156,7 +164,7 @@ class SctpClientPipelineSink extends AbstractChannelSink { private boolean started; private final AtomicBoolean wakenUp = new AtomicBoolean(); private final Object startStopLock = new Object(); - private final Queue registerTaskQueue = new LinkedTransferQueue(); + private final Queue registerTaskQueue = QueueFactory.createQueue(Runnable.class); Boss() { super(); diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpClientSocketChannelFactory.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientSocketChannelFactory.java similarity index 99% rename from src/main/java/io/netty/channel/socket/sctp/SctpClientSocketChannelFactory.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientSocketChannelFactory.java index 6972931e7a..151e490b64 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpClientSocketChannelFactory.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpClientSocketChannelFactory.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelPipeline; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpNotificationEvent.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationEvent.java similarity index 97% rename from src/main/java/io/netty/channel/socket/sctp/SctpNotificationEvent.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationEvent.java index b5dcae216e..9835dd24c7 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpNotificationEvent.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationEvent.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.Notification; import io.netty.channel.Channel; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpNotificationHandler.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationHandler.java similarity index 87% rename from src/main/java/io/netty/channel/socket/sctp/SctpNotificationHandler.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationHandler.java index 56596ae0e2..0fe6ab4094 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpNotificationHandler.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpNotificationHandler.java @@ -13,9 +13,16 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; + +import com.sun.nio.sctp.AbstractNotificationHandler; +import com.sun.nio.sctp.AssociationChangeNotification; +import com.sun.nio.sctp.HandlerResult; +import com.sun.nio.sctp.Notification; +import com.sun.nio.sctp.PeerAddressChangeNotification; +import com.sun.nio.sctp.SendFailedNotification; +import com.sun.nio.sctp.ShutdownNotification; -import com.sun.nio.sctp.*; import io.netty.channel.Channels; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpPayload.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpPayload.java similarity index 98% rename from src/main/java/io/netty/channel/socket/sctp/SctpPayload.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpPayload.java index 28a6babdaf..e773a34083 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpPayload.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpPayload.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffers; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpProviderMetadata.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpProviderMetadata.java similarity index 99% rename from src/main/java/io/netty/channel/socket/sctp/SctpProviderMetadata.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpProviderMetadata.java index 91a736f986..51902620c8 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpProviderMetadata.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpProviderMetadata.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.SctpServerChannel; import io.netty.logging.InternalLogger; @@ -37,12 +37,12 @@ import java.util.regex.Pattern; * Provides information which is specific to a NIO service provider * implementation. */ -class SctpProviderMetadata { +final class SctpProviderMetadata { static final InternalLogger logger = InternalLoggerFactory.getInstance(SctpProviderMetadata.class); private static final String CONSTRAINT_LEVEL_PROPERTY = - "io.netty.channel.socket.sctp.constraintLevel"; + "io.netty.channel.sctp.constraintLevel"; /** * 0 - no need to wake up to get / set interestOps (most cases) diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpReceiveBufferPool.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpReceiveBufferPool.java similarity index 91% rename from src/main/java/io/netty/channel/socket/sctp/SctpReceiveBufferPool.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpReceiveBufferPool.java index 6749155e4e..b664a794bc 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpReceiveBufferPool.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpReceiveBufferPool.java @@ -13,13 +13,11 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; -/** - */ final class SctpReceiveBufferPool { private static final int POOL_SIZE = 8; @@ -31,7 +29,7 @@ final class SctpReceiveBufferPool { super(); } - final ByteBuffer acquire(int size) { + ByteBuffer acquire(int size) { final SoftReference[] pool = this.pool; for (int i = 0; i < POOL_SIZE; i ++) { SoftReference ref = pool[i]; @@ -60,7 +58,7 @@ final class SctpReceiveBufferPool { return buf; } - final void release(ByteBuffer buffer) { + void release(ByteBuffer buffer) { final SoftReference[] pool = this.pool; for (int i = 0; i < POOL_SIZE; i ++) { SoftReference ref = pool[i]; @@ -72,7 +70,7 @@ final class SctpReceiveBufferPool { // pool is full - replace one final int capacity = buffer.capacity(); - for (int i = 0; i< POOL_SIZE; i ++) { + for (int i = 0; i < POOL_SIZE; i ++) { SoftReference ref = pool[i]; ByteBuffer pooled = ref.get(); if (pooled == null) { @@ -87,7 +85,7 @@ final class SctpReceiveBufferPool { } } - private static final int normalizeCapacity(int capacity) { + private static int normalizeCapacity(int capacity) { // Normalize to multiple of 1024 int q = capacity >>> 10; int r = capacity & 1023; @@ -96,4 +94,4 @@ final class SctpReceiveBufferPool { } return q << 10; } -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpSendBufferPool.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpSendBufferPool.java similarity index 94% rename from src/main/java/io/netty/channel/socket/sctp/SctpSendBufferPool.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpSendBufferPool.java index 7fdcdebabc..07d5adc8fd 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpSendBufferPool.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpSendBufferPool.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.SctpChannel; @@ -23,8 +23,6 @@ import java.io.IOException; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; -/** - */ final class SctpSendBufferPool { private static final SendBuffer EMPTY_BUFFER = new EmptySendBuffer(); @@ -33,14 +31,14 @@ final class SctpSendBufferPool { private static final int ALIGN_SHIFT = 4; private static final int ALIGN_MASK = 15; - PreallocationRef poolHead = null; + PreallocationRef poolHead; Preallocation current = new Preallocation(DEFAULT_PREALLOCATION_SIZE); SctpSendBufferPool() { super(); } - final SendBuffer acquire(Object message) { + SendBuffer acquire(Object message) { if (message instanceof SctpPayload) { return acquire((SctpPayload) message); } else { @@ -49,7 +47,7 @@ final class SctpSendBufferPool { } } - private final SendBuffer acquire(SctpPayload message) { + private SendBuffer acquire(SctpPayload message) { final ChannelBuffer src = message.getPayloadBuffer(); final int streamNo = message.getStreamIdentifier(); final int protocolId = message.getProtocolIdentifier(); @@ -99,7 +97,7 @@ final class SctpSendBufferPool { return dst; } - private final Preallocation getPreallocation() { + private Preallocation getPreallocation() { Preallocation current = this.current; if (current.refCnt == 0) { current.buffer.clear(); @@ -109,7 +107,7 @@ final class SctpSendBufferPool { return getPreallocation0(); } - private final Preallocation getPreallocation0() { + private Preallocation getPreallocation0() { PreallocationRef ref = poolHead; if (ref != null) { do { @@ -128,7 +126,7 @@ final class SctpSendBufferPool { return new Preallocation(DEFAULT_PREALLOCATION_SIZE); } - private static final int align(int pos) { + private static int align(int pos) { int q = pos >>> ALIGN_SHIFT; int r = pos & ALIGN_MASK; if (r != 0) { @@ -270,17 +268,17 @@ final class SctpSendBufferPool { } @Override - public final boolean finished() { + public boolean finished() { return true; } @Override - public final long writtenBytes() { + public long writtenBytes() { return 0; } @Override - public final long totalBytes() { + public long totalBytes() { return 0; } diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannel.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannel.java similarity index 97% rename from src/main/java/io/netty/channel/socket/sctp/SctpServerChannel.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannel.java index 3e73b49a1f..2fb186cb98 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannel.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannel.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.channel.ServerChannel; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannelConfig.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java similarity index 98% rename from src/main/java/io/netty/channel/socket/sctp/SctpServerChannelConfig.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java index f4fbc4040a..82732220a5 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannelConfig.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelConfig.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import static com.sun.nio.sctp.SctpStandardSocketOptions.*; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannelImpl.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelImpl.java similarity index 90% rename from src/main/java/io/netty/channel/socket/sctp/SctpServerChannelImpl.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelImpl.java index 24719eed73..335be780bb 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpServerChannelImpl.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerChannelImpl.java @@ -13,11 +13,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import io.netty.channel.*; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; +import static io.netty.channel.Channels.*; import java.io.IOException; import java.net.InetSocketAddress; @@ -30,7 +28,13 @@ import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import static io.netty.channel.Channels.fireChannelOpen; +import io.netty.channel.AbstractServerChannel; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelSink; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; /** */ @@ -110,12 +114,12 @@ class SctpServerChannelImpl extends AbstractServerChannel @Override public InetSocketAddress getRemoteAddress() { - return null;// not available for server channel + return null; // not available for server channel } @Override public Set getAllRemoteAddresses() { - return null;// not available for server channel + return null; // not available for server channel } @Override diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpServerPipelineSink.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerPipelineSink.java similarity index 94% rename from src/main/java/io/netty/channel/socket/sctp/SctpServerPipelineSink.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerPipelineSink.java index 8283a5b7fb..d39ca7b688 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpServerPipelineSink.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerPipelineSink.java @@ -13,23 +13,34 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import com.sun.nio.sctp.SctpChannel; -import io.netty.channel.*; -import io.netty.channel.Channel; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.internal.DeadLockProofWorker; +import static io.netty.channel.Channels.*; import java.io.IOException; import java.net.SocketAddress; import java.net.SocketTimeoutException; -import java.nio.channels.*; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; -import static io.netty.channel.Channels.*; +import com.sun.nio.sctp.SctpChannel; + +import io.netty.channel.AbstractChannelSink; +import io.netty.channel.Channel; +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelState; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.MessageEvent; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.internal.DeadLockProofWorker; /** */ diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpServerSocketChannelFactory.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerSocketChannelFactory.java similarity index 99% rename from src/main/java/io/netty/channel/socket/sctp/SctpServerSocketChannelFactory.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerSocketChannelFactory.java index 57e1fcab17..7ac54e1fdc 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpServerSocketChannelFactory.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpServerSocketChannelFactory.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelSink; diff --git a/src/main/java/io/netty/channel/socket/sctp/SctpWorker.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpWorker.java similarity index 97% rename from src/main/java/io/netty/channel/socket/sctp/SctpWorker.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SctpWorker.java index 2e40de6963..e18d6b85df 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SctpWorker.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SctpWorker.java @@ -13,33 +13,42 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; -import com.sun.nio.sctp.*; -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBufferFactory; -import io.netty.channel.Channel; -import io.netty.channel.*; -import io.netty.channel.socket.sctp.SctpSendBufferPool.SendBuffer; -import io.netty.logging.InternalLogger; -import io.netty.logging.InternalLoggerFactory; -import io.netty.util.internal.DeadLockProofWorker; +import static io.netty.channel.Channels.*; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; -import java.nio.channels.*; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.NotYetConnectedException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; import java.util.Iterator; import java.util.Queue; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import static io.netty.channel.Channels.*; +import com.sun.nio.sctp.MessageInfo; + +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBufferFactory; +import io.netty.channel.Channel; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelFuture; +import io.netty.channel.MessageEvent; +import io.netty.channel.ReceiveBufferSizePredictor; +import io.netty.channel.sctp.SctpSendBufferPool.SendBuffer; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.util.internal.DeadLockProofWorker; +import io.netty.util.internal.QueueFactory; /** */ @@ -60,8 +69,8 @@ class SctpWorker implements Runnable { private final AtomicBoolean wakenUp = new AtomicBoolean(); private final ReadWriteLock selectorGuard = new ReentrantReadWriteLock(); private final Object startStopLock = new Object(); - private final Queue registerTaskQueue = new LinkedTransferQueue(); - private final Queue writeTaskQueue = new LinkedTransferQueue(); + private final Queue registerTaskQueue = QueueFactory.createQueue(Runnable.class); + private final Queue writeTaskQueue = QueueFactory.createQueue(Runnable.class); private volatile int cancelledKeys; // should use AtomicInteger but we just need approximation private final SctpReceiveBufferPool recvBufferPool = new SctpReceiveBufferPool(); diff --git a/src/main/java/io/netty/channel/socket/sctp/SelectorUtil.java b/transport-sctp/src/main/java/io/netty/channel/sctp/SelectorUtil.java similarity index 88% rename from src/main/java/io/netty/channel/socket/sctp/SelectorUtil.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/SelectorUtil.java index 8a4bc5af29..500b5473e1 100644 --- a/src/main/java/io/netty/channel/socket/sctp/SelectorUtil.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/SelectorUtil.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; @@ -22,8 +22,6 @@ import java.io.IOException; import java.nio.channels.CancelledKeyException; import java.nio.channels.Selector; -/** - */ final class SelectorUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelectorUtil.class); @@ -32,7 +30,7 @@ final class SelectorUtil { static void select(Selector selector) throws IOException { try { - selector.select(10);// does small timeout give more throughput + less CPU usage? + selector.select(10); // does small timeout give more throughput + less CPU usage? } catch (CancelledKeyException e) { // Harmless exception - log anyway logger.debug( @@ -40,4 +38,8 @@ final class SelectorUtil { " raised by a Selector - JDK bug?", e); } } + + private SelectorUtil() { + // Unused + } } diff --git a/src/main/java/io/netty/channel/socket/sctp/package-info.java b/transport-sctp/src/main/java/io/netty/channel/sctp/package-info.java similarity index 95% rename from src/main/java/io/netty/channel/socket/sctp/package-info.java rename to transport-sctp/src/main/java/io/netty/channel/sctp/package-info.java index 95e64a58eb..d99e070321 100644 --- a/src/main/java/io/netty/channel/socket/sctp/package-info.java +++ b/transport-sctp/src/main/java/io/netty/channel/sctp/package-info.java @@ -18,4 +18,4 @@ * NIO-based socket channel * API implementation - recommended for a large number of connections (>= 1000). */ -package io.netty.channel.socket.sctp; +package io.netty.channel.sctp; diff --git a/transport/pom.xml b/transport/pom.xml new file mode 100644 index 0000000000..01f293a234 --- /dev/null +++ b/transport/pom.xml @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + io.netty + netty-parent + 4.0.0.Alpha1-SNAPSHOT + + + io.netty + netty-transport + jar + + Netty/Transport + + + + ${project.groupId} + netty-buffer + ${project.version} + + + + diff --git a/src/main/java/io/netty/bootstrap/Bootstrap.java b/transport/src/main/java/io/netty/bootstrap/Bootstrap.java similarity index 99% rename from src/main/java/io/netty/bootstrap/Bootstrap.java rename to transport/src/main/java/io/netty/bootstrap/Bootstrap.java index 76d2e82090..c1903f0365 100644 --- a/src/main/java/io/netty/bootstrap/Bootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/Bootstrap.java @@ -213,7 +213,7 @@ public class Bootstrap implements ExternalResourceReleasable { } ChannelPipeline pipeline = pipeline(); - for(Map.Entry e: pipelineMap.entrySet()) { + for (Map.Entry e: pipelineMap.entrySet()) { pipeline.addLast(e.getKey(), e.getValue()); } diff --git a/src/main/java/io/netty/bootstrap/ClientBootstrap.java b/transport/src/main/java/io/netty/bootstrap/ClientBootstrap.java similarity index 97% rename from src/main/java/io/netty/bootstrap/ClientBootstrap.java rename to transport/src/main/java/io/netty/bootstrap/ClientBootstrap.java index 1d90d9a1f9..91f1b05bd5 100644 --- a/src/main/java/io/netty/bootstrap/ClientBootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/ClientBootstrap.java @@ -209,7 +209,15 @@ public class ClientBootstrap extends Bootstrap { // Set the options. Channel ch = getFactory().newChannel(pipeline); - ch.getConfig().setOptions(getOptions()); + boolean success = false; + try { + ch.getConfig().setOptions(getOptions()); + success = true; + } finally { + if (!success) { + ch.close(); + } + } // Bind. if (localAddress != null) { diff --git a/src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java b/transport/src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java similarity index 96% rename from src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java rename to transport/src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java index cd790cf07d..b93246535f 100644 --- a/src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/ConnectionlessBootstrap.java @@ -183,8 +183,15 @@ public class ConnectionlessBootstrap extends Bootstrap { Channel ch = getFactory().newChannel(pipeline); // Apply options. - ch.getConfig().setPipelineFactory(getPipelineFactory()); - ch.getConfig().setOptions(getOptions()); + boolean success = false; + try { + ch.getConfig().setOptions(getOptions()); + success = true; + } finally { + if (!success) { + ch.close(); + } + } // Bind ChannelFuture future = ch.bind(localAddress); @@ -288,7 +295,15 @@ public class ConnectionlessBootstrap extends Bootstrap { // Set the options. Channel ch = getFactory().newChannel(pipeline); - ch.getConfig().setOptions(getOptions()); + boolean success = false; + try { + ch.getConfig().setOptions(getOptions()); + success = true; + } finally { + if (!success) { + ch.close(); + } + } // Bind. if (localAddress != null) { diff --git a/src/main/java/io/netty/bootstrap/ServerBootstrap.java b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java similarity index 98% rename from src/main/java/io/netty/bootstrap/ServerBootstrap.java rename to transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java index 24705e9a50..c8b4c23d88 100644 --- a/src/main/java/io/netty/bootstrap/ServerBootstrap.java +++ b/transport/src/main/java/io/netty/bootstrap/ServerBootstrap.java @@ -347,7 +347,11 @@ public class ServerBootstrap extends Bootstrap { ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { // Apply child options. - e.getChildChannel().getConfig().setOptions(childOptions); + try { + e.getChildChannel().getConfig().setOptions(childOptions); + } catch (Throwable t) { + Channels.fireExceptionCaught(e.getChildChannel(), t); + } ctx.sendUpstream(e); } diff --git a/src/main/java/io/netty/bootstrap/package-info.java b/transport/src/main/java/io/netty/bootstrap/package-info.java similarity index 100% rename from src/main/java/io/netty/bootstrap/package-info.java rename to transport/src/main/java/io/netty/bootstrap/package-info.java diff --git a/src/main/java/io/netty/channel/AbstractChannel.java b/transport/src/main/java/io/netty/channel/AbstractChannel.java similarity index 100% rename from src/main/java/io/netty/channel/AbstractChannel.java rename to transport/src/main/java/io/netty/channel/AbstractChannel.java diff --git a/src/main/java/io/netty/channel/AbstractChannelSink.java b/transport/src/main/java/io/netty/channel/AbstractChannelSink.java similarity index 100% rename from src/main/java/io/netty/channel/AbstractChannelSink.java rename to transport/src/main/java/io/netty/channel/AbstractChannelSink.java diff --git a/src/main/java/io/netty/channel/AbstractServerChannel.java b/transport/src/main/java/io/netty/channel/AbstractServerChannel.java similarity index 100% rename from src/main/java/io/netty/channel/AbstractServerChannel.java rename to transport/src/main/java/io/netty/channel/AbstractServerChannel.java diff --git a/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictor.java b/transport/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictor.java similarity index 100% rename from src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictor.java rename to transport/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictor.java diff --git a/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictorFactory.java b/transport/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictorFactory.java similarity index 100% rename from src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictorFactory.java rename to transport/src/main/java/io/netty/channel/AdaptiveReceiveBufferSizePredictorFactory.java diff --git a/src/main/java/io/netty/channel/Channel.java b/transport/src/main/java/io/netty/channel/Channel.java similarity index 100% rename from src/main/java/io/netty/channel/Channel.java rename to transport/src/main/java/io/netty/channel/Channel.java diff --git a/src/main/java/io/netty/channel/ChannelConfig.java b/transport/src/main/java/io/netty/channel/ChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelConfig.java rename to transport/src/main/java/io/netty/channel/ChannelConfig.java diff --git a/src/main/java/io/netty/channel/ChannelDownstreamHandler.java b/transport/src/main/java/io/netty/channel/ChannelDownstreamHandler.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelDownstreamHandler.java rename to transport/src/main/java/io/netty/channel/ChannelDownstreamHandler.java diff --git a/src/main/java/io/netty/channel/ChannelEvent.java b/transport/src/main/java/io/netty/channel/ChannelEvent.java similarity index 99% rename from src/main/java/io/netty/channel/ChannelEvent.java rename to transport/src/main/java/io/netty/channel/ChannelEvent.java index f5687ad5d8..48436d3f04 100644 --- a/src/main/java/io/netty/channel/ChannelEvent.java +++ b/transport/src/main/java/io/netty/channel/ChannelEvent.java @@ -55,7 +55,7 @@ import io.netty.channel.socket.ServerSocketChannel; * *
      * - * + * * * * diff --git a/src/main/java/io/netty/channel/ChannelException.java b/transport/src/main/java/io/netty/channel/ChannelException.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelException.java rename to transport/src/main/java/io/netty/channel/ChannelException.java diff --git a/src/main/java/io/netty/channel/ChannelFactory.java b/transport/src/main/java/io/netty/channel/ChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelFactory.java rename to transport/src/main/java/io/netty/channel/ChannelFactory.java diff --git a/src/main/java/io/netty/channel/ChannelFuture.java b/transport/src/main/java/io/netty/channel/ChannelFuture.java similarity index 97% rename from src/main/java/io/netty/channel/ChannelFuture.java rename to transport/src/main/java/io/netty/channel/ChannelFuture.java index 48baa7b1ff..c2be184732 100644 --- a/src/main/java/io/netty/channel/ChannelFuture.java +++ b/transport/src/main/java/io/netty/channel/ChannelFuture.java @@ -18,7 +18,6 @@ package io.netty.channel; import java.util.concurrent.TimeUnit; import io.netty.bootstrap.ClientBootstrap; -import io.netty.handler.execution.ExecutionHandler; /** * The result of an asynchronous {@link Channel} I/O operation. @@ -84,9 +83,8 @@ import io.netty.handler.execution.ExecutionHandler; * *

      Do not call {@link #await()} inside {@link ChannelHandler}

      *

      - * The event handler methods in {@link ChannelHandler} is often called by - * an I/O thread unless an {@link ExecutionHandler} is in the - * {@link ChannelPipeline}. If {@link #await()} is called by an event handler + * The event handler methods in {@link ChannelHandler} is usually called by + * an I/O thread. If {@link #await()} is called by an event handler * method, which is called by the I/O thread, the I/O operation it is waiting * for might never be complete because {@link #await()} can block the I/O * operation it is waiting for, which is a dead lock. @@ -260,6 +258,12 @@ public interface ChannelFuture { */ void removeListener(ChannelFutureListener listener); + /** + * Rethrows the exception that caused this future fail if this future is + * complete and failed. + */ + ChannelFuture rethrowIfFailed() throws Exception; + /** * Waits for this future to be completed. * diff --git a/src/main/java/io/netty/channel/ChannelFutureAggregator.java b/transport/src/main/java/io/netty/channel/ChannelFutureAggregator.java similarity index 98% rename from src/main/java/io/netty/channel/ChannelFutureAggregator.java rename to transport/src/main/java/io/netty/channel/ChannelFutureAggregator.java index d0aa0feb24..e18f44cff3 100644 --- a/src/main/java/io/netty/channel/ChannelFutureAggregator.java +++ b/transport/src/main/java/io/netty/channel/ChannelFutureAggregator.java @@ -36,7 +36,7 @@ public class ChannelFutureAggregator implements ChannelFutureListener { } public void addFuture(ChannelFuture future) { - synchronized(this) { + synchronized (this) { if (pendingFutures == null) { pendingFutures = new HashSet(); } @@ -74,4 +74,4 @@ public class ChannelFutureAggregator implements ChannelFutureListener { } } -} \ No newline at end of file +} diff --git a/src/main/java/io/netty/channel/ChannelFutureListener.java b/transport/src/main/java/io/netty/channel/ChannelFutureListener.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelFutureListener.java rename to transport/src/main/java/io/netty/channel/ChannelFutureListener.java diff --git a/src/main/java/io/netty/channel/ChannelFutureProgressListener.java b/transport/src/main/java/io/netty/channel/ChannelFutureProgressListener.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelFutureProgressListener.java rename to transport/src/main/java/io/netty/channel/ChannelFutureProgressListener.java diff --git a/src/main/java/io/netty/channel/ChannelHandler.java b/transport/src/main/java/io/netty/channel/ChannelHandler.java similarity index 99% rename from src/main/java/io/netty/channel/ChannelHandler.java rename to transport/src/main/java/io/netty/channel/ChannelHandler.java index a0f3849920..4bd6bfd4f4 100644 --- a/src/main/java/io/netty/channel/ChannelHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelHandler.java @@ -218,7 +218,7 @@ public interface ChannelHandler { *

      * This annotation is provided for documentation purpose, just like * the JCIP annotations. - */ + */ @Inherited @Documented @Target(ElementType.TYPE) diff --git a/src/main/java/io/netty/channel/ChannelHandlerContext.java b/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java similarity index 98% rename from src/main/java/io/netty/channel/ChannelHandlerContext.java rename to transport/src/main/java/io/netty/channel/ChannelHandlerContext.java index aa6be8def0..078139be69 100644 --- a/src/main/java/io/netty/channel/ChannelHandlerContext.java +++ b/transport/src/main/java/io/netty/channel/ChannelHandlerContext.java @@ -51,7 +51,7 @@ package io.netty.channel; * public void login(String username, password) { * {@link Channels}.write( * this.ctx, - * {@link Channels}.succeededFuture(this.ctx.getChannel()), + * {@link Channels}.succeededFuture(this.ctx.getChannel()), * new LoginMessage(username, password)); * } * ... diff --git a/src/main/java/io/netty/channel/ChannelHandlerLifeCycleException.java b/transport/src/main/java/io/netty/channel/ChannelHandlerLifeCycleException.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelHandlerLifeCycleException.java rename to transport/src/main/java/io/netty/channel/ChannelHandlerLifeCycleException.java diff --git a/src/main/java/io/netty/channel/ChannelLocal.java b/transport/src/main/java/io/netty/channel/ChannelLocal.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelLocal.java rename to transport/src/main/java/io/netty/channel/ChannelLocal.java diff --git a/src/main/java/io/netty/channel/ChannelPipeline.java b/transport/src/main/java/io/netty/channel/ChannelPipeline.java similarity index 96% rename from src/main/java/io/netty/channel/ChannelPipeline.java rename to transport/src/main/java/io/netty/channel/ChannelPipeline.java index 6a222a7a10..cbdeeab097 100644 --- a/src/main/java/io/netty/channel/ChannelPipeline.java +++ b/transport/src/main/java/io/netty/channel/ChannelPipeline.java @@ -22,9 +22,6 @@ import java.util.Map; import java.util.NoSuchElementException; import io.netty.buffer.ChannelBuffer; -import io.netty.handler.execution.ExecutionHandler; -import io.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; -import io.netty.handler.ssl.SslHandler; /** @@ -157,7 +154,7 @@ import io.netty.handler.ssl.SslHandler; *

    • Protocol Decoder - translates binary data (e.g. {@link ChannelBuffer}) * into a Java object.
    • *
    • Protocol Encoder - translates a Java object into binary data.
    • - *
    • {@link ExecutionHandler} - applies a thread model.
    • + *
    • ExecutionHandler - applies a thread model.
    • *
    • Business Logic Handler - performs the actual business logic * (e.g. database access).
    • * @@ -168,15 +165,15 @@ import io.netty.handler.ssl.SslHandler; * {@link ChannelPipeline} pipeline = {@link Channels#pipeline() Channels.pipeline()}; * pipeline.addLast("decoder", new MyProtocolDecoder()); * pipeline.addLast("encoder", new MyProtocolEncoder()); - * pipeline.addLast("executor", new {@link ExecutionHandler}(new {@link OrderedMemoryAwareThreadPoolExecutor}(16, 1048576, 1048576))); + * pipeline.addLast("executor", new ExecutionHandler(...)); * pipeline.addLast("handler", new MyBusinessLogicHandler()); * * *

      Thread safety

      *

      * A {@link ChannelHandler} can be added or removed at any time because a - * {@link ChannelPipeline} is thread safe. For example, you can insert a - * {@link SslHandler} when sensitive information is about to be exchanged, + * {@link ChannelPipeline} is thread safe. For example, you can insert an + * encryption handler when sensitive information is about to be exchanged, * and remove it after the exchange. * *

      Pitfall

      @@ -218,7 +215,7 @@ public interface ChannelPipeline { * @throws NullPointerException * if the specified name or handler is {@code null} */ - void addFirst (String name, ChannelHandler handler); + void addFirst(String name, ChannelHandler handler); /** * Appends a {@link ChannelHandler} at the last position of this pipeline. @@ -231,7 +228,7 @@ public interface ChannelPipeline { * @throws NullPointerException * if the specified name or handler is {@code null} */ - void addLast (String name, ChannelHandler handler); + void addLast(String name, ChannelHandler handler); /** * Inserts a {@link ChannelHandler} before an existing handler of this @@ -265,7 +262,7 @@ public interface ChannelPipeline { * @throws NullPointerException * if the specified baseName, name, or handler is {@code null} */ - void addAfter (String baseName, String name, ChannelHandler handler); + void addAfter(String baseName, String name, ChannelHandler handler); /** * Removes the specified {@link ChannelHandler} from this pipeline. diff --git a/src/main/java/io/netty/channel/ChannelPipelineException.java b/transport/src/main/java/io/netty/channel/ChannelPipelineException.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelPipelineException.java rename to transport/src/main/java/io/netty/channel/ChannelPipelineException.java diff --git a/src/main/java/io/netty/channel/ChannelPipelineFactory.java b/transport/src/main/java/io/netty/channel/ChannelPipelineFactory.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelPipelineFactory.java rename to transport/src/main/java/io/netty/channel/ChannelPipelineFactory.java diff --git a/src/main/java/io/netty/channel/ChannelSink.java b/transport/src/main/java/io/netty/channel/ChannelSink.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelSink.java rename to transport/src/main/java/io/netty/channel/ChannelSink.java diff --git a/src/main/java/io/netty/channel/ChannelState.java b/transport/src/main/java/io/netty/channel/ChannelState.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelState.java rename to transport/src/main/java/io/netty/channel/ChannelState.java diff --git a/src/main/java/io/netty/channel/ChannelStateEvent.java b/transport/src/main/java/io/netty/channel/ChannelStateEvent.java similarity index 100% rename from src/main/java/io/netty/channel/ChannelStateEvent.java rename to transport/src/main/java/io/netty/channel/ChannelStateEvent.java diff --git a/src/main/java/io/netty/channel/ChannelUpstreamHandler.java b/transport/src/main/java/io/netty/channel/ChannelUpstreamHandler.java similarity index 90% rename from src/main/java/io/netty/channel/ChannelUpstreamHandler.java rename to transport/src/main/java/io/netty/channel/ChannelUpstreamHandler.java index a17fe80be7..5203e44b19 100644 --- a/src/main/java/io/netty/channel/ChannelUpstreamHandler.java +++ b/transport/src/main/java/io/netty/channel/ChannelUpstreamHandler.java @@ -15,11 +15,6 @@ */ package io.netty.channel; -import java.util.concurrent.Executor; - -import io.netty.handler.execution.ExecutionHandler; - - /** * Handles or intercepts an upstream {@link ChannelEvent}, and sends a * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. @@ -78,11 +73,7 @@ import io.netty.handler.execution.ExecutionHandler; * {@link Channel}; the I/O thread of some transport can serve more than one * {@link Channel} (e.g. NIO transport), while the I/O thread of other * transports can serve only one (e.g. OIO transport). - *

      - * However, if you add an {@link ExecutionHandler} to a {@link ChannelPipeline}, - * this behavior changes depending on what {@link Executor} was employed to - * dispatch the events. Please refer to {@link ExecutionHandler} for more - * information. + * * @apiviz.exclude ^io\.netty\.handler\..*$ */ public interface ChannelUpstreamHandler extends ChannelHandler { diff --git a/src/main/java/io/netty/channel/Channels.java b/transport/src/main/java/io/netty/channel/Channels.java similarity index 99% rename from src/main/java/io/netty/channel/Channels.java rename to transport/src/main/java/io/netty/channel/Channels.java index 37d0529aae..e5852d2ced 100644 --- a/src/main/java/io/netty/channel/Channels.java +++ b/transport/src/main/java/io/netty/channel/Channels.java @@ -47,7 +47,7 @@ import io.netty.util.internal.ConversionUtil; * {@link ChannelHandlerContext#sendDownstream(ChannelEvent)} by yourself. * @apiviz.landmark */ -public class Channels { +public final class Channels { // pipeline factory methods diff --git a/src/main/java/io/netty/channel/ChildChannelStateEvent.java b/transport/src/main/java/io/netty/channel/ChildChannelStateEvent.java similarity index 100% rename from src/main/java/io/netty/channel/ChildChannelStateEvent.java rename to transport/src/main/java/io/netty/channel/ChildChannelStateEvent.java diff --git a/src/main/java/io/netty/channel/CompleteChannelFuture.java b/transport/src/main/java/io/netty/channel/CompleteChannelFuture.java similarity index 100% rename from src/main/java/io/netty/channel/CompleteChannelFuture.java rename to transport/src/main/java/io/netty/channel/CompleteChannelFuture.java diff --git a/src/main/java/io/netty/channel/DefaultChannelConfig.java b/transport/src/main/java/io/netty/channel/DefaultChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultChannelConfig.java rename to transport/src/main/java/io/netty/channel/DefaultChannelConfig.java diff --git a/src/main/java/io/netty/channel/DefaultChannelFuture.java b/transport/src/main/java/io/netty/channel/DefaultChannelFuture.java similarity index 96% rename from src/main/java/io/netty/channel/DefaultChannelFuture.java rename to transport/src/main/java/io/netty/channel/DefaultChannelFuture.java index 8153c0f6e8..c9fbc72445 100644 --- a/src/main/java/io/netty/channel/DefaultChannelFuture.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelFuture.java @@ -175,6 +175,28 @@ public class DefaultChannelFuture implements ChannelFuture { } } + @Override + public ChannelFuture rethrowIfFailed() throws Exception { + if (!isDone()) { + return this; + } + + Throwable cause = getCause(); + if (cause == null) { + return this; + } + + if (cause instanceof Exception) { + throw (Exception) cause; + } + + if (cause instanceof Error) { + throw (Error) cause; + } + + throw new RuntimeException(cause); + } + @Override public ChannelFuture await() throws InterruptedException { if (Thread.interrupted()) { diff --git a/src/main/java/io/netty/channel/DefaultChannelPipeline.java b/transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultChannelPipeline.java rename to transport/src/main/java/io/netty/channel/DefaultChannelPipeline.java diff --git a/src/main/java/io/netty/channel/DefaultChildChannelStateEvent.java b/transport/src/main/java/io/netty/channel/DefaultChildChannelStateEvent.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultChildChannelStateEvent.java rename to transport/src/main/java/io/netty/channel/DefaultChildChannelStateEvent.java diff --git a/src/main/java/io/netty/channel/DefaultExceptionEvent.java b/transport/src/main/java/io/netty/channel/DefaultExceptionEvent.java similarity index 94% rename from src/main/java/io/netty/channel/DefaultExceptionEvent.java rename to transport/src/main/java/io/netty/channel/DefaultExceptionEvent.java index d18383b14a..d77abab7c7 100644 --- a/src/main/java/io/netty/channel/DefaultExceptionEvent.java +++ b/transport/src/main/java/io/netty/channel/DefaultExceptionEvent.java @@ -17,8 +17,6 @@ package io.netty.channel; import static io.netty.channel.Channels.*; -import io.netty.util.internal.StackTraceSimplifier; - /** * The default {@link ExceptionEvent} implementation. */ @@ -39,7 +37,6 @@ public class DefaultExceptionEvent implements ExceptionEvent { } this.channel = channel; this.cause = cause; - StackTraceSimplifier.simplify(cause); } @Override diff --git a/src/main/java/io/netty/channel/DefaultFileRegion.java b/transport/src/main/java/io/netty/channel/DefaultFileRegion.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultFileRegion.java rename to transport/src/main/java/io/netty/channel/DefaultFileRegion.java diff --git a/src/main/java/io/netty/channel/DefaultServerChannelConfig.java b/transport/src/main/java/io/netty/channel/DefaultServerChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultServerChannelConfig.java rename to transport/src/main/java/io/netty/channel/DefaultServerChannelConfig.java diff --git a/src/main/java/io/netty/channel/DefaultWriteCompletionEvent.java b/transport/src/main/java/io/netty/channel/DefaultWriteCompletionEvent.java similarity index 100% rename from src/main/java/io/netty/channel/DefaultWriteCompletionEvent.java rename to transport/src/main/java/io/netty/channel/DefaultWriteCompletionEvent.java diff --git a/src/main/java/io/netty/channel/DownstreamChannelStateEvent.java b/transport/src/main/java/io/netty/channel/DownstreamChannelStateEvent.java similarity index 100% rename from src/main/java/io/netty/channel/DownstreamChannelStateEvent.java rename to transport/src/main/java/io/netty/channel/DownstreamChannelStateEvent.java diff --git a/src/main/java/io/netty/channel/DownstreamMessageEvent.java b/transport/src/main/java/io/netty/channel/DownstreamMessageEvent.java similarity index 100% rename from src/main/java/io/netty/channel/DownstreamMessageEvent.java rename to transport/src/main/java/io/netty/channel/DownstreamMessageEvent.java diff --git a/src/main/java/io/netty/channel/ExceptionEvent.java b/transport/src/main/java/io/netty/channel/ExceptionEvent.java similarity index 100% rename from src/main/java/io/netty/channel/ExceptionEvent.java rename to transport/src/main/java/io/netty/channel/ExceptionEvent.java diff --git a/src/main/java/io/netty/channel/FailedChannelFuture.java b/transport/src/main/java/io/netty/channel/FailedChannelFuture.java similarity index 82% rename from src/main/java/io/netty/channel/FailedChannelFuture.java rename to transport/src/main/java/io/netty/channel/FailedChannelFuture.java index 1e1f6e2860..44f3e12a43 100644 --- a/src/main/java/io/netty/channel/FailedChannelFuture.java +++ b/transport/src/main/java/io/netty/channel/FailedChannelFuture.java @@ -47,4 +47,17 @@ public class FailedChannelFuture extends CompleteChannelFuture { public boolean isSuccess() { return false; } + + @Override + public ChannelFuture rethrowIfFailed() throws Exception { + if (cause instanceof Exception) { + throw (Exception) cause; + } + + if (cause instanceof Error) { + throw (Error) cause; + } + + throw new RuntimeException(cause); + } } diff --git a/src/main/java/io/netty/channel/FileRegion.java b/transport/src/main/java/io/netty/channel/FileRegion.java similarity index 100% rename from src/main/java/io/netty/channel/FileRegion.java rename to transport/src/main/java/io/netty/channel/FileRegion.java diff --git a/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictor.java b/transport/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictor.java similarity index 100% rename from src/main/java/io/netty/channel/FixedReceiveBufferSizePredictor.java rename to transport/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictor.java diff --git a/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictorFactory.java b/transport/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictorFactory.java similarity index 100% rename from src/main/java/io/netty/channel/FixedReceiveBufferSizePredictorFactory.java rename to transport/src/main/java/io/netty/channel/FixedReceiveBufferSizePredictorFactory.java diff --git a/src/main/java/io/netty/channel/LifeCycleAwareChannelHandler.java b/transport/src/main/java/io/netty/channel/LifeCycleAwareChannelHandler.java similarity index 100% rename from src/main/java/io/netty/channel/LifeCycleAwareChannelHandler.java rename to transport/src/main/java/io/netty/channel/LifeCycleAwareChannelHandler.java diff --git a/src/main/java/io/netty/channel/MessageEvent.java b/transport/src/main/java/io/netty/channel/MessageEvent.java similarity index 100% rename from src/main/java/io/netty/channel/MessageEvent.java rename to transport/src/main/java/io/netty/channel/MessageEvent.java diff --git a/src/main/java/io/netty/channel/ReceiveBufferSizePredictor.java b/transport/src/main/java/io/netty/channel/ReceiveBufferSizePredictor.java similarity index 100% rename from src/main/java/io/netty/channel/ReceiveBufferSizePredictor.java rename to transport/src/main/java/io/netty/channel/ReceiveBufferSizePredictor.java diff --git a/src/main/java/io/netty/channel/ReceiveBufferSizePredictorFactory.java b/transport/src/main/java/io/netty/channel/ReceiveBufferSizePredictorFactory.java similarity index 100% rename from src/main/java/io/netty/channel/ReceiveBufferSizePredictorFactory.java rename to transport/src/main/java/io/netty/channel/ReceiveBufferSizePredictorFactory.java diff --git a/src/main/java/io/netty/channel/ServerChannel.java b/transport/src/main/java/io/netty/channel/ServerChannel.java similarity index 100% rename from src/main/java/io/netty/channel/ServerChannel.java rename to transport/src/main/java/io/netty/channel/ServerChannel.java diff --git a/src/main/java/io/netty/channel/ServerChannelFactory.java b/transport/src/main/java/io/netty/channel/ServerChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/ServerChannelFactory.java rename to transport/src/main/java/io/netty/channel/ServerChannelFactory.java diff --git a/src/main/java/io/netty/channel/SimpleChannelDownstreamHandler.java b/transport/src/main/java/io/netty/channel/SimpleChannelDownstreamHandler.java similarity index 100% rename from src/main/java/io/netty/channel/SimpleChannelDownstreamHandler.java rename to transport/src/main/java/io/netty/channel/SimpleChannelDownstreamHandler.java diff --git a/src/main/java/io/netty/channel/SimpleChannelHandler.java b/transport/src/main/java/io/netty/channel/SimpleChannelHandler.java similarity index 100% rename from src/main/java/io/netty/channel/SimpleChannelHandler.java rename to transport/src/main/java/io/netty/channel/SimpleChannelHandler.java diff --git a/src/main/java/io/netty/channel/SimpleChannelUpstreamHandler.java b/transport/src/main/java/io/netty/channel/SimpleChannelUpstreamHandler.java similarity index 100% rename from src/main/java/io/netty/channel/SimpleChannelUpstreamHandler.java rename to transport/src/main/java/io/netty/channel/SimpleChannelUpstreamHandler.java diff --git a/src/main/java/io/netty/channel/SucceededChannelFuture.java b/transport/src/main/java/io/netty/channel/SucceededChannelFuture.java similarity index 92% rename from src/main/java/io/netty/channel/SucceededChannelFuture.java rename to transport/src/main/java/io/netty/channel/SucceededChannelFuture.java index 4f55c3d9c9..8c198b6d01 100644 --- a/src/main/java/io/netty/channel/SucceededChannelFuture.java +++ b/transport/src/main/java/io/netty/channel/SucceededChannelFuture.java @@ -40,4 +40,9 @@ public class SucceededChannelFuture extends CompleteChannelFuture { public boolean isSuccess() { return true; } + + @Override + public ChannelFuture rethrowIfFailed() throws Exception { + return this; + } } diff --git a/src/main/java/io/netty/channel/UpstreamChannelStateEvent.java b/transport/src/main/java/io/netty/channel/UpstreamChannelStateEvent.java similarity index 100% rename from src/main/java/io/netty/channel/UpstreamChannelStateEvent.java rename to transport/src/main/java/io/netty/channel/UpstreamChannelStateEvent.java diff --git a/src/main/java/io/netty/channel/UpstreamMessageEvent.java b/transport/src/main/java/io/netty/channel/UpstreamMessageEvent.java similarity index 100% rename from src/main/java/io/netty/channel/UpstreamMessageEvent.java rename to transport/src/main/java/io/netty/channel/UpstreamMessageEvent.java diff --git a/src/main/java/io/netty/channel/WriteCompletionEvent.java b/transport/src/main/java/io/netty/channel/WriteCompletionEvent.java similarity index 100% rename from src/main/java/io/netty/channel/WriteCompletionEvent.java rename to transport/src/main/java/io/netty/channel/WriteCompletionEvent.java diff --git a/src/main/java/io/netty/channel/group/ChannelGroup.java b/transport/src/main/java/io/netty/channel/group/ChannelGroup.java similarity index 100% rename from src/main/java/io/netty/channel/group/ChannelGroup.java rename to transport/src/main/java/io/netty/channel/group/ChannelGroup.java diff --git a/src/main/java/io/netty/channel/group/ChannelGroupFuture.java b/transport/src/main/java/io/netty/channel/group/ChannelGroupFuture.java similarity index 97% rename from src/main/java/io/netty/channel/group/ChannelGroupFuture.java rename to transport/src/main/java/io/netty/channel/group/ChannelGroupFuture.java index c6c8480b96..2313f3a792 100644 --- a/src/main/java/io/netty/channel/group/ChannelGroupFuture.java +++ b/transport/src/main/java/io/netty/channel/group/ChannelGroupFuture.java @@ -22,9 +22,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; import io.netty.channel.MessageEvent; -import io.netty.handler.execution.ExecutionHandler; /** * The result of an asynchronous {@link ChannelGroup} operation. @@ -69,8 +67,7 @@ import io.netty.handler.execution.ExecutionHandler; *

      Do not call {@link #await()} inside {@link ChannelHandler}

      *

      * The event handler methods in {@link ChannelHandler} is often called by - * an I/O thread unless an {@link ExecutionHandler} is in the - * {@link ChannelPipeline}. If {@link #await()} is called by an event handler + * an I/O thread. If {@link #await()} is called by an event handler * method, which is called by the I/O thread, the I/O operation it is waiting * for might never be complete because {@link #await()} can block the I/O * operation it is waiting for, which is a dead lock. @@ -107,6 +104,7 @@ import io.netty.handler.execution.ExecutionHandler; * where it is more convenient to call {@link #await()}. In such a case, please * make sure you do not call {@link #await()} in an I/O thread. Otherwise, * {@link IllegalStateException} will be raised to prevent a dead lock. + * * @apiviz.owns io.netty.channel.group.ChannelGroupFutureListener - - notifies */ public interface ChannelGroupFuture extends Iterable { diff --git a/src/main/java/io/netty/channel/group/ChannelGroupFutureListener.java b/transport/src/main/java/io/netty/channel/group/ChannelGroupFutureListener.java similarity index 100% rename from src/main/java/io/netty/channel/group/ChannelGroupFutureListener.java rename to transport/src/main/java/io/netty/channel/group/ChannelGroupFutureListener.java diff --git a/src/main/java/io/netty/channel/group/CombinedIterator.java b/transport/src/main/java/io/netty/channel/group/CombinedIterator.java similarity index 100% rename from src/main/java/io/netty/channel/group/CombinedIterator.java rename to transport/src/main/java/io/netty/channel/group/CombinedIterator.java diff --git a/src/main/java/io/netty/channel/group/DefaultChannelGroup.java b/transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java similarity index 100% rename from src/main/java/io/netty/channel/group/DefaultChannelGroup.java rename to transport/src/main/java/io/netty/channel/group/DefaultChannelGroup.java diff --git a/src/main/java/io/netty/channel/group/DefaultChannelGroupFuture.java b/transport/src/main/java/io/netty/channel/group/DefaultChannelGroupFuture.java similarity index 100% rename from src/main/java/io/netty/channel/group/DefaultChannelGroupFuture.java rename to transport/src/main/java/io/netty/channel/group/DefaultChannelGroupFuture.java diff --git a/src/main/java/io/netty/channel/group/package-info.java b/transport/src/main/java/io/netty/channel/group/package-info.java similarity index 100% rename from src/main/java/io/netty/channel/group/package-info.java rename to transport/src/main/java/io/netty/channel/group/package-info.java diff --git a/src/main/java/io/netty/channel/iostream/IOStreamAddress.java b/transport/src/main/java/io/netty/channel/iostream/IoStreamAddress.java similarity index 87% rename from src/main/java/io/netty/channel/iostream/IOStreamAddress.java rename to transport/src/main/java/io/netty/channel/iostream/IoStreamAddress.java index a5005a1c79..ec75a4e4c5 100755 --- a/src/main/java/io/netty/channel/iostream/IOStreamAddress.java +++ b/transport/src/main/java/io/netty/channel/iostream/IoStreamAddress.java @@ -22,19 +22,17 @@ import java.net.SocketAddress; /** * A {@link java.net.SocketAddress} implementation holding an * {@link java.io.InputStream} and an {@link java.io.OutputStream} instance used - * as "remote" address to connect to with a {@link IOStreamChannel}. + * as "remote" address to connect to with a {@link IoStreamChannel}. */ -public class IOStreamAddress extends SocketAddress { +public class IoStreamAddress extends SocketAddress { - /** - */ private static final long serialVersionUID = -4382415449059935960L; private final InputStream inputStream; private final OutputStream outputStream; - public IOStreamAddress(final InputStream inputStream, final OutputStream outputStream) { + public IoStreamAddress(final InputStream inputStream, final OutputStream outputStream) { this.inputStream = inputStream; this.outputStream = outputStream; diff --git a/src/main/java/io/netty/channel/iostream/IOStreamChannel.java b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannel.java similarity index 71% rename from src/main/java/io/netty/channel/iostream/IOStreamChannel.java rename to transport/src/main/java/io/netty/channel/iostream/IoStreamChannel.java index f38c78ba76..6077d7c23b 100755 --- a/src/main/java/io/netty/channel/iostream/IOStreamChannel.java +++ b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannel.java @@ -15,33 +15,38 @@ */ package io.netty.channel.iostream; -import io.netty.channel.*; - import java.net.SocketAddress; +import io.netty.channel.AbstractChannel; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFactory; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelSink; + /** * A channel to an {@link java.io.InputStream} and an * {@link java.io.OutputStream}. */ -public class IOStreamChannel extends AbstractChannel { +public class IoStreamChannel extends AbstractChannel { - IOStreamChannel(final ChannelFactory factory, final ChannelPipeline pipeline, final ChannelSink sink) { + IoStreamChannel(final ChannelFactory factory, final ChannelPipeline pipeline, final ChannelSink sink) { super(null, factory, pipeline, sink); } @Override public ChannelConfig getConfig() { - return ((IOStreamChannelSink) getPipeline().getSink()).getConfig(); + return ((IoStreamChannelSink) getPipeline().getSink()).getConfig(); } @Override public boolean isBound() { - return ((IOStreamChannelSink) getPipeline().getSink()).isBound(); + return ((IoStreamChannelSink) getPipeline().getSink()).isBound(); } @Override public boolean isConnected() { - return ((IOStreamChannelSink) getPipeline().getSink()).isConnected(); + return ((IoStreamChannelSink) getPipeline().getSink()).isConnected(); } @Override @@ -51,7 +56,7 @@ public class IOStreamChannel extends AbstractChannel { @Override public SocketAddress getRemoteAddress() { - return ((IOStreamChannelSink) getPipeline().getSink()).getRemoteAddress(); + return ((IoStreamChannelSink) getPipeline().getSink()).getRemoteAddress(); } @Override diff --git a/src/main/java/io/netty/channel/iostream/IOStreamChannelFactory.java b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannelFactory.java similarity index 85% rename from src/main/java/io/netty/channel/iostream/IOStreamChannelFactory.java rename to transport/src/main/java/io/netty/channel/iostream/IoStreamChannelFactory.java index 17b7246dac..74e2f09dc4 100755 --- a/src/main/java/io/netty/channel/iostream/IOStreamChannelFactory.java +++ b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannelFactory.java @@ -27,22 +27,22 @@ import io.netty.util.internal.ExecutorUtil; import java.util.concurrent.ExecutorService; /** - * A {@link io.netty.channel.ChannelFactory} for creating {@link IOStreamChannel} instances. + * A {@link io.netty.channel.ChannelFactory} for creating {@link IoStreamChannel} instances. */ -public class IOStreamChannelFactory implements ChannelFactory { +public class IoStreamChannelFactory implements ChannelFactory { private final ChannelGroup channels = new DefaultChannelGroup("IOStreamChannelFactory-ChannelGroup"); private final ExecutorService executorService; - public IOStreamChannelFactory(ExecutorService executorService) { + public IoStreamChannelFactory(ExecutorService executorService) { this.executorService = executorService; } @Override public Channel newChannel(final ChannelPipeline pipeline) { - IOStreamChannelSink sink = new IOStreamChannelSink(executorService); - IOStreamChannel channel = new IOStreamChannel(this, pipeline, sink); + IoStreamChannelSink sink = new IoStreamChannelSink(executorService); + IoStreamChannel channel = new IoStreamChannel(this, pipeline, sink); sink.setChannel(channel); channels.add(channel); return channel; diff --git a/src/main/java/io/netty/channel/iostream/IOStreamChannelSink.java b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannelSink.java similarity index 84% rename from src/main/java/io/netty/channel/iostream/IOStreamChannelSink.java rename to transport/src/main/java/io/netty/channel/iostream/IoStreamChannelSink.java index ff0a891101..a0d75ceef7 100755 --- a/src/main/java/io/netty/channel/iostream/IOStreamChannelSink.java +++ b/transport/src/main/java/io/netty/channel/iostream/IoStreamChannelSink.java @@ -15,27 +15,35 @@ */ package io.netty.channel.iostream; -import io.netty.buffer.ChannelBuffer; -import io.netty.buffer.ChannelBuffers; -import io.netty.channel.*; +import static io.netty.channel.Channels.*; import java.io.OutputStream; import java.io.PushbackInputStream; import java.util.concurrent.ExecutorService; -import static io.netty.channel.Channels.*; +import io.netty.buffer.ChannelBuffer; +import io.netty.buffer.ChannelBuffers; +import io.netty.channel.AbstractChannelSink; +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelEvent; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelState; +import io.netty.channel.ChannelStateEvent; +import io.netty.channel.DefaultChannelConfig; +import io.netty.channel.MessageEvent; /** * A {@link io.netty.channel.ChannelSink} implementation which reads from * an {@link java.io.InputStream} and writes to an {@link java.io.OutputStream}. */ -public class IOStreamChannelSink extends AbstractChannelSink { +public class IoStreamChannelSink extends AbstractChannelSink { private static class ReadRunnable implements Runnable { - private final IOStreamChannelSink channelSink; + private final IoStreamChannelSink channelSink; - public ReadRunnable(final IOStreamChannelSink channelSink) { + public ReadRunnable(final IoStreamChannelSink channelSink) { this.channelSink = channelSink; } @@ -80,9 +88,9 @@ public class IOStreamChannelSink extends AbstractChannelSink { private final ExecutorService executorService; - private IOStreamChannel channel; + private IoStreamChannel channel; - public IOStreamChannelSink(final ExecutorService executorService) { + public IoStreamChannelSink(final ExecutorService executorService) { this.executorService = executorService; } @@ -90,7 +98,7 @@ public class IOStreamChannelSink extends AbstractChannelSink { return inputStream != null && outputStream != null; } - public IOStreamAddress getRemoteAddress() { + public IoStreamAddress getRemoteAddress() { return remoteAddress; } @@ -102,11 +110,11 @@ public class IOStreamChannelSink extends AbstractChannelSink { return config; } - public void setChannel(final IOStreamChannel channel) { + public void setChannel(final IoStreamChannel channel) { this.channel = channel; } - private IOStreamAddress remoteAddress; + private IoStreamAddress remoteAddress; private OutputStream outputStream; @@ -131,7 +139,7 @@ public class IOStreamChannelSink extends AbstractChannelSink { if (Boolean.FALSE.equals(value)) { outputStream = null; inputStream = null; - ((IOStreamChannel) e.getChannel()).doSetClosed(); + ((IoStreamChannel) e.getChannel()).doSetClosed(); } break; @@ -140,7 +148,7 @@ public class IOStreamChannelSink extends AbstractChannelSink { case CONNECTED: if (value != null) { - remoteAddress = (IOStreamAddress) value; + remoteAddress = (IoStreamAddress) value; outputStream = remoteAddress.getOutputStream(); inputStream = new PushbackInputStream(remoteAddress.getInputStream()); executorService.execute(new ReadRunnable(this)); diff --git a/transport/src/main/java/io/netty/channel/iostream/package-info.java b/transport/src/main/java/io/netty/channel/iostream/package-info.java new file mode 100644 index 0000000000..1107973b28 --- /dev/null +++ b/transport/src/main/java/io/netty/channel/iostream/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright 2011 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +/** + * A blocking transport which uses an existing {@link java.io.InputStream} and + * {@link java.io.OutputStream}. + * + * @apiviz.exclude ^java\.lang\. + * @apiviz.exclude Channel$ + */ +package io.netty.channel.iostream; diff --git a/src/main/java/io/netty/channel/local/DefaultLocalChannel.java b/transport/src/main/java/io/netty/channel/local/DefaultLocalChannel.java similarity index 98% rename from src/main/java/io/netty/channel/local/DefaultLocalChannel.java rename to transport/src/main/java/io/netty/channel/local/DefaultLocalChannel.java index cb34481046..0507ea959a 100644 --- a/src/main/java/io/netty/channel/local/DefaultLocalChannel.java +++ b/transport/src/main/java/io/netty/channel/local/DefaultLocalChannel.java @@ -171,7 +171,7 @@ final class DefaultLocalChannel extends AbstractChannel implements LocalChannel void flushWriteBuffer() { DefaultLocalChannel pairedChannel = this.pairedChannel; if (pairedChannel != null) { - if (pairedChannel.isConnected()){ + if (pairedChannel.isConnected()) { // Channel is open and connected and channelConnected event has // been fired. if (!delivering.get()) { @@ -179,7 +179,7 @@ final class DefaultLocalChannel extends AbstractChannel implements LocalChannel try { for (;;) { MessageEvent e = writeBuffer.poll(); - if(e == null) { + if (e == null) { break; } @@ -206,7 +206,7 @@ final class DefaultLocalChannel extends AbstractChannel implements LocalChannel for (;;) { MessageEvent e = writeBuffer.poll(); - if(e == null) { + if (e == null) { break; } diff --git a/src/main/java/io/netty/channel/local/DefaultLocalClientChannelFactory.java b/transport/src/main/java/io/netty/channel/local/DefaultLocalClientChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/local/DefaultLocalClientChannelFactory.java rename to transport/src/main/java/io/netty/channel/local/DefaultLocalClientChannelFactory.java diff --git a/src/main/java/io/netty/channel/local/DefaultLocalServerChannel.java b/transport/src/main/java/io/netty/channel/local/DefaultLocalServerChannel.java similarity index 100% rename from src/main/java/io/netty/channel/local/DefaultLocalServerChannel.java rename to transport/src/main/java/io/netty/channel/local/DefaultLocalServerChannel.java diff --git a/src/main/java/io/netty/channel/local/DefaultLocalServerChannelFactory.java b/transport/src/main/java/io/netty/channel/local/DefaultLocalServerChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/local/DefaultLocalServerChannelFactory.java rename to transport/src/main/java/io/netty/channel/local/DefaultLocalServerChannelFactory.java diff --git a/src/main/java/io/netty/channel/local/LocalAddress.java b/transport/src/main/java/io/netty/channel/local/LocalAddress.java similarity index 99% rename from src/main/java/io/netty/channel/local/LocalAddress.java rename to transport/src/main/java/io/netty/channel/local/LocalAddress.java index 266f63e376..1853690d82 100644 --- a/src/main/java/io/netty/channel/local/LocalAddress.java +++ b/transport/src/main/java/io/netty/channel/local/LocalAddress.java @@ -104,7 +104,7 @@ public final class LocalAddress extends SocketAddress implements Comparable{ +abstract class AbstractWriteRequestQueue implements BlockingQueue { protected final BlockingQueue queue; diff --git a/src/main/java/io/netty/channel/socket/nio/DefaultNioDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/DefaultNioDatagramChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/DefaultNioDatagramChannelConfig.java rename to transport/src/main/java/io/netty/channel/socket/nio/DefaultNioDatagramChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/nio/DefaultNioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/DefaultNioSocketChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/DefaultNioSocketChannelConfig.java rename to transport/src/main/java/io/netty/channel/socket/nio/DefaultNioSocketChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java index 56d3fe8cc7..a4b7803cfe 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioAcceptedSocketChannel.java @@ -24,8 +24,6 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelSink; -/** - */ final class NioAcceptedSocketChannel extends NioSocketChannel { final Thread bossThread; diff --git a/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java index c1a1af47d7..571a832e29 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannel.java @@ -28,8 +28,6 @@ import io.netty.channel.ChannelSink; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; -/** - */ final class NioClientSocketChannel extends NioSocketChannel { private static final InternalLogger logger = diff --git a/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java similarity index 98% rename from src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java index 28cc631877..f91e07cfc0 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketChannelFactory.java @@ -117,7 +117,7 @@ public class NioClientSocketChannelFactory implements ClientSocketChannelFactory public NioClientSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int workerCount) { - this(bossExecutor, workerExecutor, DEFAULT_BOSS_COUNT, workerCount); + this(bossExecutor, workerExecutor, DEFAULT_BOSS_COUNT, workerCount); } /** @@ -135,7 +135,7 @@ public class NioClientSocketChannelFactory implements ClientSocketChannelFactory public NioClientSocketChannelFactory( Executor bossExecutor, Executor workerExecutor, int bossCount, int workerCount) { - + if (bossExecutor == null) { throw new NullPointerException("bossExecutor"); } diff --git a/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java similarity index 97% rename from src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java index 8fbe800ba6..0b269857e7 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioClientSocketPipelineSink.java @@ -45,8 +45,6 @@ import io.netty.logging.InternalLoggerFactory; import io.netty.util.internal.DeadLockProofWorker; import io.netty.util.internal.QueueFactory; -/** - */ class NioClientSocketPipelineSink extends AbstractChannelSink { static final InternalLogger logger = @@ -54,7 +52,7 @@ class NioClientSocketPipelineSink extends AbstractChannelSink { final Executor bossExecutor; - private final Boss bosses[]; + private final Boss[] bosses; private final NioWorker[] workers; private final AtomicInteger bossIndex = new AtomicInteger(); @@ -63,12 +61,12 @@ class NioClientSocketPipelineSink extends AbstractChannelSink { NioClientSocketPipelineSink( Executor bossExecutor, Executor workerExecutor, int bossCount, int workerCount) { - + this.bossExecutor = bossExecutor; bosses = new Boss[bossCount]; for (int i = 0; i < bosses.length; i ++) { - bosses[i] = new Boss(); + bosses[i] = new Boss(); } workers = new NioWorker[workerCount]; @@ -366,7 +364,13 @@ class NioClientSocketPipelineSink extends AbstractChannelSink { ConnectException cause = null; for (SelectionKey k: keys) { if (!k.isValid()) { - close(k); + // Comment the close call again as it gave us major problems with ClosedChannelExceptions. + // + // See: + // * https://github.com/netty/netty/issues/142 + // * https://github.com/netty/netty/issues/138 + // + //close(k); continue; } diff --git a/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java index 27cfe152b8..89d54527cc 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java @@ -44,7 +44,7 @@ import io.netty.util.internal.ThreadLocalBoolean; /** * Provides an NIO based {@link io.netty.channel.socket.DatagramChannel}. */ -class NioDatagramChannel extends AbstractChannel +final class NioDatagramChannel extends AbstractChannel implements io.netty.channel.socket.DatagramChannel { /** @@ -315,7 +315,7 @@ class NioDatagramChannel extends AbstractChannel /** * WriteTask is a simple runnable performs writes by delegating the {@link NioDatagramWorker}. - */ + */ private final class WriteTask implements Runnable { WriteTask() { } diff --git a/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/NioDatagramChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioDatagramPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramPipelineSink.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/NioDatagramPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioDatagramPipelineSink.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java index 4eb550cbb5..eff53e3433 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramWorker.java @@ -822,7 +822,7 @@ class NioDatagramWorker implements Runnable { /** * This runnable's task. Does the actual registering by calling the * underlying DatagramChannels peer DatagramSocket register method. - */ + */ @Override public void run() { final SocketAddress localAddress = channel.getLocalAddress(); diff --git a/src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java b/transport/src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java index 8b422b42f3..b4152e7b89 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioProviderMetadata.java @@ -37,7 +37,7 @@ import io.netty.util.internal.SystemPropertyUtil; * Provides information which is specific to a NIO service provider * implementation. */ -class NioProviderMetadata { +final class NioProviderMetadata { static final InternalLogger logger = InternalLoggerFactory.getInstance(NioProviderMetadata.class); diff --git a/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java similarity index 98% rename from src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java index 8358017edd..91b6ca0cb2 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannel.java @@ -34,9 +34,7 @@ import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; -/** - */ -class NioServerSocketChannel extends AbstractServerChannel +final class NioServerSocketChannel extends AbstractServerChannel implements io.netty.channel.socket.ServerSocketChannel { private static final InternalLogger logger = diff --git a/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/NioServerSocketChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java index 37767fe999..7663886d52 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioServerSocketPipelineSink.java @@ -41,8 +41,6 @@ import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; import io.netty.util.internal.DeadLockProofWorker; -/** - */ class NioServerSocketPipelineSink extends AbstractChannelSink { static final InternalLogger logger = diff --git a/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java index 57c534b0f7..e73d133d2b 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannel.java @@ -35,8 +35,6 @@ import io.netty.channel.MessageEvent; import io.netty.channel.socket.nio.SocketSendBufferPool.SendBuffer; import io.netty.util.internal.ThreadLocalBoolean; -/** - */ class NioSocketChannel extends AbstractChannel implements io.netty.channel.socket.SocketChannel { diff --git a/src/main/java/io/netty/channel/socket/nio/NioSocketChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannelConfig.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/NioSocketChannelConfig.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioSocketChannelConfig.java diff --git a/src/main/java/io/netty/channel/socket/nio/NioWorker.java b/transport/src/main/java/io/netty/channel/socket/nio/NioWorker.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/NioWorker.java rename to transport/src/main/java/io/netty/channel/socket/nio/NioWorker.java index 33caf4cb3f..942d0d133d 100644 --- a/src/main/java/io/netty/channel/socket/nio/NioWorker.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/NioWorker.java @@ -49,8 +49,6 @@ import io.netty.logging.InternalLoggerFactory; import io.netty.util.internal.DeadLockProofWorker; import io.netty.util.internal.QueueFactory; -/** - */ class NioWorker implements Runnable { private static final InternalLogger logger = @@ -486,7 +484,9 @@ class NioWorker implements Runnable { } catch (AsynchronousCloseException e) { // Doesn't need a user attention - ignore. } catch (Throwable t) { - buf.release(); + if (buf != null) { + buf.release(); + } channel.currentWriteEvent = null; channel.currentWriteBuffer = null; buf = null; diff --git a/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java b/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java similarity index 96% rename from src/main/java/io/netty/channel/socket/nio/SelectorUtil.java rename to transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java index 4e3570fd12..79ade13920 100644 --- a/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/SelectorUtil.java @@ -22,8 +22,6 @@ import java.nio.channels.Selector; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; -/** - */ final class SelectorUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SelectorUtil.class); @@ -40,4 +38,8 @@ final class SelectorUtil { " raised by a Selector - JDK bug?", e); } } + + private SelectorUtil() { + // Unused + } } diff --git a/src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java b/transport/src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java similarity index 97% rename from src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java rename to transport/src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java index 7385eb7457..de2b53ff83 100644 --- a/src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/SocketReceiveBufferPool.java @@ -18,8 +18,6 @@ package io.netty.channel.socket.nio; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; -/** - */ final class SocketReceiveBufferPool { private static final int POOL_SIZE = 8; @@ -52,7 +50,6 @@ final class SocketReceiveBufferPool { } ByteBuffer buf = ByteBuffer.allocateDirect(normalizeCapacity(size)); - buf.clear(); return buf; } @@ -68,7 +65,7 @@ final class SocketReceiveBufferPool { // pool is full - replace one final int capacity = buffer.capacity(); - for (int i = 0; i< POOL_SIZE; i ++) { + for (int i = 0; i < POOL_SIZE; i ++) { SoftReference ref = pool[i]; ByteBuffer pooled = ref.get(); if (pooled == null) { diff --git a/src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java b/transport/src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java similarity index 99% rename from src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java rename to transport/src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java index 5b03846ec7..bd0ebbd3f5 100644 --- a/src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java +++ b/transport/src/main/java/io/netty/channel/socket/nio/SocketSendBufferPool.java @@ -25,8 +25,6 @@ import java.nio.channels.WritableByteChannel; import io.netty.buffer.ChannelBuffer; import io.netty.channel.FileRegion; -/** - */ final class SocketSendBufferPool { private static final SendBuffer EMPTY_BUFFER = new EmptySendBuffer(); @@ -35,7 +33,7 @@ final class SocketSendBufferPool { private static final int ALIGN_SHIFT = 4; private static final int ALIGN_MASK = 15; - PreallocationRef poolHead = null; + PreallocationRef poolHead; Preallocation current = new Preallocation(DEFAULT_PREALLOCATION_SIZE); SocketSendBufferPool() { diff --git a/src/main/java/io/netty/channel/socket/nio/package-info.java b/transport/src/main/java/io/netty/channel/socket/nio/package-info.java similarity index 100% rename from src/main/java/io/netty/channel/socket/nio/package-info.java rename to transport/src/main/java/io/netty/channel/socket/nio/package-info.java diff --git a/src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java similarity index 97% rename from src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java index 5bd4c6174c..58af115aba 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioAcceptedSocketChannel.java @@ -28,9 +28,7 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelSink; -/** - */ -class OioAcceptedSocketChannel extends OioSocketChannel { +final class OioAcceptedSocketChannel extends OioSocketChannel { private final PushbackInputStream in; private final OutputStream out; diff --git a/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java similarity index 96% rename from src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java index 02a0b32712..57219543ee 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannel.java @@ -25,9 +25,7 @@ import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelSink; -/** - */ -class OioClientSocketChannel extends OioSocketChannel { +final class OioClientSocketChannel extends OioSocketChannel { volatile PushbackInputStream in; volatile OutputStream out; diff --git a/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/oio/OioClientSocketChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java index 43851b3a8c..e5cf415a02 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioClientSocketPipelineSink.java @@ -31,8 +31,6 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.util.internal.DeadLockProofWorker; -/** - */ class OioClientSocketPipelineSink extends AbstractChannelSink { private final Executor workerExecutor; diff --git a/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java index 140e5fa15c..841fd1b316 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannel.java @@ -35,8 +35,6 @@ import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramChannelConfig; import io.netty.channel.socket.DefaultDatagramChannelConfig; -/** - */ final class OioDatagramChannel extends AbstractChannel implements DatagramChannel { diff --git a/src/main/java/io/netty/channel/socket/oio/OioDatagramChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/oio/OioDatagramChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioDatagramChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java index 5c2a9e4aae..3cf3e6baf6 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramPipelineSink.java @@ -30,8 +30,6 @@ import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.util.internal.DeadLockProofWorker; -/** - */ class OioDatagramPipelineSink extends AbstractChannelSink { private final Executor workerExecutor; diff --git a/src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java index 78f25b474a..ab6ffbd277 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioDatagramWorker.java @@ -28,8 +28,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ReceiveBufferSizePredictor; -/** - */ class OioDatagramWorker implements Runnable { private final OioDatagramChannel channel; diff --git a/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java similarity index 98% rename from src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java index d3b725948f..87b256f4a2 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannel.java @@ -34,9 +34,7 @@ import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; -/** - */ -class OioServerSocketChannel extends AbstractServerChannel +final class OioServerSocketChannel extends AbstractServerChannel implements ServerSocketChannel { private static final InternalLogger logger = diff --git a/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelFactory.java b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelFactory.java similarity index 100% rename from src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelFactory.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketChannelFactory.java diff --git a/src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java index be1d567266..1e594ace15 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioServerSocketPipelineSink.java @@ -36,8 +36,6 @@ import io.netty.logging.InternalLogger; import io.netty.logging.InternalLoggerFactory; import io.netty.util.internal.DeadLockProofWorker; -/** - */ class OioServerSocketPipelineSink extends AbstractChannelSink { static final InternalLogger logger = diff --git a/src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java b/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java index 29d7178ebb..bd1ccdb588 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioSocketChannel.java @@ -31,8 +31,6 @@ import io.netty.channel.socket.DefaultSocketChannelConfig; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannelConfig; -/** - */ abstract class OioSocketChannel extends AbstractChannel implements SocketChannel { diff --git a/src/main/java/io/netty/channel/socket/oio/OioWorker.java b/transport/src/main/java/io/netty/channel/socket/oio/OioWorker.java similarity index 99% rename from src/main/java/io/netty/channel/socket/oio/OioWorker.java rename to transport/src/main/java/io/netty/channel/socket/oio/OioWorker.java index 8135f3e1ab..9afe62ba62 100644 --- a/src/main/java/io/netty/channel/socket/oio/OioWorker.java +++ b/transport/src/main/java/io/netty/channel/socket/oio/OioWorker.java @@ -30,8 +30,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.FileRegion; -/** - */ class OioWorker implements Runnable { private static final Pattern SOCKET_CLOSED_MESSAGE = Pattern.compile( diff --git a/src/main/java/io/netty/channel/socket/oio/package-info.java b/transport/src/main/java/io/netty/channel/socket/oio/package-info.java similarity index 100% rename from src/main/java/io/netty/channel/socket/oio/package-info.java rename to transport/src/main/java/io/netty/channel/socket/oio/package-info.java diff --git a/src/main/java/io/netty/channel/socket/package-info.java b/transport/src/main/java/io/netty/channel/socket/package-info.java similarity index 100% rename from src/main/java/io/netty/channel/socket/package-info.java rename to transport/src/main/java/io/netty/channel/socket/package-info.java diff --git a/src/test/java/io/netty/bootstrap/BootstrapOrderedMapTest.java b/transport/src/test/java/io/netty/bootstrap/BootstrapOrderedMapTest.java similarity index 100% rename from src/test/java/io/netty/bootstrap/BootstrapOrderedMapTest.java rename to transport/src/test/java/io/netty/bootstrap/BootstrapOrderedMapTest.java diff --git a/src/test/java/io/netty/bootstrap/BootstrapTest.java b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java similarity index 94% rename from src/test/java/io/netty/bootstrap/BootstrapTest.java rename to transport/src/test/java/io/netty/bootstrap/BootstrapTest.java index 5255be1ddf..fdf24488c7 100644 --- a/src/test/java/io/netty/bootstrap/BootstrapTest.java +++ b/transport/src/test/java/io/netty/bootstrap/BootstrapTest.java @@ -25,11 +25,15 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Map.Entry; +import io.netty.channel.ChannelDownstreamHandler; +import io.netty.channel.ChannelEvent; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; -import io.netty.util.DummyHandler; +import io.netty.channel.ChannelUpstreamHandler; + import org.junit.Test; @@ -338,4 +342,18 @@ public class BootstrapTest { public void shouldNotAllowNullOptionMap() { new Bootstrap().setOptions(null); } + + private class DummyHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler { + + public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) + throws Exception { + ctx.sendUpstream(e); + } + + public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) + throws Exception { + ctx.sendDownstream(e); + } + } + } diff --git a/src/test/java/io/netty/channel/CompleteChannelFutureTest.java b/transport/src/test/java/io/netty/channel/CompleteChannelFutureTest.java similarity index 96% rename from src/test/java/io/netty/channel/CompleteChannelFutureTest.java rename to transport/src/test/java/io/netty/channel/CompleteChannelFutureTest.java index 29a5fedb50..b1de5862f5 100644 --- a/src/test/java/io/netty/channel/CompleteChannelFutureTest.java +++ b/transport/src/test/java/io/netty/channel/CompleteChannelFutureTest.java @@ -23,9 +23,6 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; - -/** - */ public class CompleteChannelFutureTest { private final Channel channel = createMock(Channel.class); @@ -102,6 +99,11 @@ public class CompleteChannelFutureTest { public boolean isSuccess() { throw new Error(); } + + @Override + public ChannelFuture rethrowIfFailed() throws Exception { + throw new Error(); + } } private static class ExpectedError extends Error { diff --git a/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java b/transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java similarity index 100% rename from src/test/java/io/netty/channel/DefaultChannelPipelineTest.java rename to transport/src/test/java/io/netty/channel/DefaultChannelPipelineTest.java diff --git a/src/test/java/io/netty/channel/FailedChannelFutureTest.java b/transport/src/test/java/io/netty/channel/FailedChannelFutureTest.java similarity index 99% rename from src/test/java/io/netty/channel/FailedChannelFutureTest.java rename to transport/src/test/java/io/netty/channel/FailedChannelFutureTest.java index bf43e07fdc..a6d697a2ea 100644 --- a/src/test/java/io/netty/channel/FailedChannelFutureTest.java +++ b/transport/src/test/java/io/netty/channel/FailedChannelFutureTest.java @@ -20,9 +20,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class FailedChannelFutureTest { @Test public void testConstantProperties() { diff --git a/src/test/java/io/netty/channel/SucceededChannelFutureTest.java b/transport/src/test/java/io/netty/channel/SucceededChannelFutureTest.java similarity index 99% rename from src/test/java/io/netty/channel/SucceededChannelFutureTest.java rename to transport/src/test/java/io/netty/channel/SucceededChannelFutureTest.java index a29d022e94..f1ae135f72 100644 --- a/src/test/java/io/netty/channel/SucceededChannelFutureTest.java +++ b/transport/src/test/java/io/netty/channel/SucceededChannelFutureTest.java @@ -20,9 +20,6 @@ import static org.junit.Assert.*; import org.junit.Test; - -/** - */ public class SucceededChannelFutureTest { @Test public void testConstantProperties() {

      Event nameEvent type and conditionMeaningEvent nameEvent type and conditionMeaning
      {@code "messageReceived"}