Merge remote branch 'upstream/master'

This commit is contained in:
Jestan Nirojan 2012-03-05 20:56:45 +05:30
commit c40de99083
125 changed files with 3544 additions and 3202 deletions

View File

@ -821,6 +821,81 @@ public final class ChannelBuffers {
return new ReadOnlyChannelBuffer(buffer);
}
/**
* Create a {@link ChannelBuffer} that holds all the given values as int's
*
*/
public static ChannelBuffer wrapInt(int... values) {
if (values == null || values.length == 0) {
return EMPTY_BUFFER;
}
ChannelBuffer buffer = buffer(values.length * 4);
for (int v: values) {
buffer.writeInt(v);
}
return buffer;
}
/**
* Create a {@link ChannelBuffer} that holds all the given values as short's
*
*/
public static ChannelBuffer wrapShort(int... values) {
if (values == null || values.length == 0) {
return EMPTY_BUFFER;
}
ChannelBuffer buffer = buffer(values.length * 2);
for (int v: values) {
buffer.writeShort(v);
}
return buffer;
}
/**
* Create a {@link ChannelBuffer} that holds all the given values as medium's
*
*/
public static ChannelBuffer wrapMedium(int... values) {
if (values == null || values.length == 0) {
return EMPTY_BUFFER;
}
ChannelBuffer buffer = buffer(values.length * 3);
for (int v: values) {
buffer.writeMedium(v);
}
return buffer;
}
/**
* Create a {@link ChannelBuffer} that holds all the given values as long's
*
*/
public static ChannelBuffer wrapLong(long... values) {
if (values == null || values.length == 0) {
return EMPTY_BUFFER;
}
ChannelBuffer buffer = buffer(values.length * 8);
for (long v: values) {
buffer.writeLong(v);
}
return buffer;
}
/**
* Create a {@link ChannelBuffer} that holds all the given values as boolean's
*
*/
public static ChannelBuffer wrapBoolean(boolean... values) {
if (values == null || values.length == 0) {
return EMPTY_BUFFER;
}
ChannelBuffer buffer = buffer(values.length);
for (boolean v: values) {
buffer.writeBoolean(v);
}
return buffer;
}
/**
* Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
* of the specified buffer's readable bytes.

View File

@ -425,4 +425,70 @@ public class ChannelBuffersTest {
// Expected
}
}
@Test
public void testWrapInt() {
ChannelBuffer buffer = ChannelBuffers.wrapInt(1,4);
assertEquals(8, buffer.capacity());
assertEquals(1, buffer.readInt());
assertEquals(4, buffer.readInt());
assertFalse(buffer.readable());
assertEquals(0, ChannelBuffers.wrapInt(null).capacity());
assertEquals(0, ChannelBuffers.wrapInt(new int[0]).capacity());
}
@Test
public void testWrapShort() {
ChannelBuffer buffer = ChannelBuffers.wrapShort(1,4);
assertEquals(4, buffer.capacity());
assertEquals(1, buffer.readShort());
assertEquals(4, buffer.readShort());
assertFalse(buffer.readable());
assertEquals(0, ChannelBuffers.wrapShort(null).capacity());
assertEquals(0, ChannelBuffers.wrapShort(new int[0]).capacity());
}
@Test
public void testWrapMedium() {
ChannelBuffer buffer = ChannelBuffers.wrapMedium(1,4);
assertEquals(6, buffer.capacity());
assertEquals(1, buffer.readMedium());
assertEquals(4, buffer.readMedium());
assertFalse(buffer.readable());
assertEquals(0, ChannelBuffers.wrapMedium(null).capacity());
assertEquals(0, ChannelBuffers.wrapMedium(new int[0]).capacity());
}
@Test
public void testWrapLong() {
ChannelBuffer buffer = ChannelBuffers.wrapLong(1,4);
assertEquals(16, buffer.capacity());
assertEquals(1, buffer.readLong());
assertEquals(4, buffer.readLong());
assertFalse(buffer.readable());
assertEquals(0, ChannelBuffers.wrapLong(null).capacity());
assertEquals(0, ChannelBuffers.wrapLong(new long[0]).capacity());
}
@Test
public void testWrapBoolean() {
ChannelBuffer buffer = ChannelBuffers.wrapBoolean(true, false);
assertEquals(2, buffer.capacity());
assertEquals(true, buffer.readBoolean());
assertEquals(false, buffer.readBoolean());
assertFalse(buffer.readable());
assertEquals(0, ChannelBuffers.wrapBoolean(null).capacity());
assertEquals(0, ChannelBuffers.wrapBoolean(new boolean[0]).capacity());
}
}

View File

@ -16,17 +16,11 @@
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

View File

@ -15,18 +15,12 @@
*/
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

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,28 +13,12 @@
* 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.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.*;
@ -48,8 +32,8 @@ public class SpdyFrameDecoder extends FrameDecoder {
private final int maxFrameSize;
private final int maxHeaderSize;
private final DecoderEmbedder<ChannelBuffer> headerBlockDecompressor =
new DecoderEmbedder<ChannelBuffer>(new ZlibDecoder(SPDY_DICT));
private final SpdyHeaderBlockDecompressor headerBlockDecompressor =
SpdyHeaderBlockDecompressor.newInstance();
/**
* Creates a new instance with the default {@code maxChunkSize (8192)},
@ -129,7 +113,9 @@ public class SpdyFrameDecoder extends FrameDecoder {
int type = getUnsignedShort(buffer, typeOffset);
buffer.skipBytes(SPDY_HEADER_SIZE);
return decodeControlFrame(type, flags, buffer.readBytes(dataLength));
int readerIndex = buffer.readerIndex();
buffer.skipBytes(dataLength);
return decodeControlFrame(type, flags, buffer.slice(readerIndex, dataLength));
} else {
// Decode data frame common header
int streamID = getUnsignedInt(buffer, frameOffset);
@ -181,7 +167,7 @@ public class SpdyFrameDecoder extends FrameDecoder {
spdySynStreamFrame.setLast(last);
spdySynStreamFrame.setUnidirectional(unid);
decodeHeaderBlock(spdySynStreamFrame, decompress(data));
decodeHeaderBlock(spdySynStreamFrame, data);
return spdySynStreamFrame;
@ -199,7 +185,7 @@ public class SpdyFrameDecoder extends FrameDecoder {
last = (flags & SPDY_FLAG_FIN) != 0;
spdySynReplyFrame.setLast(last);
decodeHeaderBlock(spdySynReplyFrame, decompress(data));
decodeHeaderBlock(spdySynReplyFrame, data);
return spdySynReplyFrame;
@ -299,7 +285,7 @@ public class SpdyFrameDecoder extends FrameDecoder {
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamID);
decodeHeaderBlock(spdyHeadersFrame, decompress(data));
decodeHeaderBlock(spdyHeadersFrame, data);
return spdyHeadersFrame;
@ -311,31 +297,38 @@ public class SpdyFrameDecoder extends FrameDecoder {
}
}
private ChannelBuffer decompress(ChannelBuffer compressed) throws Exception {
if ((compressed.readableBytes() == 2) &&
(compressed.getShort(compressed.readerIndex()) == 0)) {
return compressed;
private boolean ensureBytes(ChannelBuffer decompressed, int bytes) throws Exception {
if (decompressed.readableBytes() >= bytes) {
return true;
}
headerBlockDecompressor.offer(compressed);
return headerBlockDecompressor.poll();
decompressed.discardReadBytes();
headerBlockDecompressor.decode(decompressed);
return decompressed.readableBytes() >= bytes;
}
private void decodeHeaderBlock(SpdyHeaderBlock headerFrame, ChannelBuffer headerBlock)
throws Exception {
if (headerBlock.readableBytes() < 2) {
if ((headerBlock.readableBytes() == 2) &&
(headerBlock.getShort(headerBlock.readerIndex()) == 0)) {
return;
}
headerBlockDecompressor.setInput(headerBlock);
ChannelBuffer decompressed = ChannelBuffers.dynamicBuffer(8192);
headerBlockDecompressor.decode(decompressed);
if (decompressed.readableBytes() < 2) {
throw new SpdyProtocolException(
"Received invalid header block");
}
int headerSize = 0;
int numEntries = getUnsignedShort(headerBlock, headerBlock.readerIndex());
headerBlock.skipBytes(2);
int numEntries = decompressed.readUnsignedShort();
for (int i = 0; i < numEntries; i ++) {
if (headerBlock.readableBytes() < 2) {
if (!ensureBytes(decompressed, 2)) {
throw new SpdyProtocolException(
"Received invalid header block");
}
int nameLength = getUnsignedShort(headerBlock, headerBlock.readerIndex());
headerBlock.skipBytes(2);
int nameLength = decompressed.readUnsignedShort();
if (nameLength == 0) {
headerFrame.setInvalid();
return;
@ -345,23 +338,22 @@ public class SpdyFrameDecoder extends FrameDecoder {
throw new SpdyProtocolException(
"Header block exceeds " + maxHeaderSize);
}
if (headerBlock.readableBytes() < nameLength) {
if (!ensureBytes(decompressed, nameLength)) {
throw new SpdyProtocolException(
"Received invalid header block");
}
byte[] nameBytes = new byte[nameLength];
headerBlock.readBytes(nameBytes);
decompressed.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) {
if (!ensureBytes(decompressed, 2)) {
throw new SpdyProtocolException(
"Received invalid header block");
}
int valueLength = getUnsignedShort(headerBlock, headerBlock.readerIndex());
headerBlock.skipBytes(2);
int valueLength = decompressed.readUnsignedShort();
if (valueLength == 0) {
headerFrame.setInvalid();
return;
@ -371,15 +363,15 @@ public class SpdyFrameDecoder extends FrameDecoder {
throw new SpdyProtocolException(
"Header block exceeds " + maxHeaderSize);
}
if (headerBlock.readableBytes() < valueLength) {
if (!ensureBytes(decompressed, valueLength)) {
throw new SpdyProtocolException(
"Received invalid header block");
}
byte[] valueBytes = new byte[valueLength];
headerBlock.readBytes(valueBytes);
decompressed.readBytes(valueBytes);
int index = 0;
int offset = 0;
while (index < valueBytes.length) {
while (index < valueLength) {
while (index < valueBytes.length && valueBytes[index] != (byte) 0) {
index ++;
}

View File

@ -13,42 +13,28 @@
* 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 io.netty.handler.codec.spdy.SpdyCodecUtil.*;
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.ChannelEvent;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.compression.ZlibEncoder;
import io.netty.handler.codec.embedder.EncoderEmbedder;
import io.netty.channel.ChannelStateEvent;
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<ChannelBuffer> headerBlockCompressor;
private volatile boolean finished;
private final SpdyHeaderBlockCompressor headerBlockCompressor;
/**
* Creates a new instance with the default {@code compressionLevel (6)},
@ -63,8 +49,27 @@ public class SpdyFrameEncoder extends OneToOneEncoder {
*/
public SpdyFrameEncoder(int compressionLevel, int windowBits, int memLevel) {
super();
headerBlockCompressor = new EncoderEmbedder<ChannelBuffer>(
new ZlibEncoder(compressionLevel, windowBits, memLevel, SPDY_DICT));
headerBlockCompressor = SpdyHeaderBlockCompressor.newInstance(compressionLevel, windowBits, memLevel);
}
@Override
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) {
synchronized (headerBlockCompressor) {
finished = true;
headerBlockCompressor.end();
}
}
}
}
super.handleDownstream(ctx, evt);
}
@Override
@ -278,7 +283,13 @@ public class SpdyFrameEncoder extends OneToOneEncoder {
if (uncompressed.readableBytes() == 0) {
return ChannelBuffers.EMPTY_BUFFER;
}
headerBlockCompressor.offer(uncompressed);
return headerBlockCompressor.poll();
ChannelBuffer compressed = ChannelBuffers.dynamicBuffer();
synchronized (headerBlockCompressor) {
if (!finished) {
headerBlockCompressor.setInput(uncompressed);
headerBlockCompressor.encode(compressed);
}
}
return compressed;
}
}

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
package io.netty.handler.codec.spdy;
import java.util.zip.Deflater;
import io.netty.buffer.ChannelBuffer;
abstract class SpdyHeaderBlockCompressor {
private static final boolean USE_ZLIB;
static {
boolean java7 = false;
try {
Deflater.class.getDeclaredMethod(
"deflate",
new Class<?>[] { byte[].class, int.class, int.class, int.class });
java7 = true;
} catch (Exception e) {
// Ignore
}
USE_ZLIB = java7;
}
static SpdyHeaderBlockCompressor newInstance(
int compressionLevel, int windowBits, int memLevel) {
if (USE_ZLIB) {
return new SpdyHeaderBlockZlibCompressor(compressionLevel);
} else {
return new SpdyHeaderBlockJZlibCompressor(
compressionLevel, windowBits, memLevel);
}
}
abstract void setInput(ChannelBuffer decompressed);
abstract void encode(ChannelBuffer compressed);
abstract void end();
}

View File

@ -0,0 +1,28 @@
/*
* 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.
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.ChannelBuffer;
abstract class SpdyHeaderBlockDecompressor {
static SpdyHeaderBlockDecompressor newInstance() {
return new SpdyHeaderBlockJZlibDecompressor();
}
abstract void setInput(ChannelBuffer compressed);
abstract void decode(ChannelBuffer decompressed);
}

View File

@ -0,0 +1,98 @@
/*
* 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.
*/
package io.netty.handler.codec.spdy;
import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
import io.netty.buffer.ChannelBuffer;
import io.netty.handler.codec.compression.CompressionException;
import io.netty.util.internal.jzlib.JZlib;
import io.netty.util.internal.jzlib.ZStream;
class SpdyHeaderBlockJZlibCompressor extends SpdyHeaderBlockCompressor {
private final ZStream z = new ZStream();
public SpdyHeaderBlockJZlibCompressor(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)");
}
int resultCode = z.deflateInit(
compressionLevel, windowBits, memLevel, JZlib.W_ZLIB);
if (resultCode != JZlib.Z_OK) {
throw new CompressionException(
"failed to initialize an SPDY header block deflater: " + resultCode);
} else {
resultCode = z.deflateSetDictionary(SPDY_DICT, SPDY_DICT.length);
if (resultCode != JZlib.Z_OK) {
throw new CompressionException(
"failed to set the SPDY dictionary: " + resultCode);
}
}
}
@Override
public void setInput(ChannelBuffer decompressed) {
byte[] in = new byte[decompressed.readableBytes()];
decompressed.readBytes(in);
z.next_in = in;
z.next_in_index = 0;
z.avail_in = in.length;
}
@Override
public void encode(ChannelBuffer compressed) {
try {
byte[] out = new byte[(int) Math.ceil(z.next_in.length * 1.001) + 12];
z.next_out = out;
z.next_out_index = 0;
z.avail_out = out.length;
int resultCode = z.deflate(JZlib.Z_SYNC_FLUSH);
if (resultCode != JZlib.Z_OK) {
throw new CompressionException("compression failure: " + resultCode);
}
if (z.next_out_index != 0) {
compressed.writeBytes(out, 0, z.next_out_index);
}
} finally {
// Deference the external references explicitly to tell the VM that
// the allocated byte arrays are temporary so that the call stack
// can be utilized.
// I'm not sure if the modern VMs do this optimization though.
z.next_in = null;
z.next_out = null;
}
}
@Override
public void end() {
z.deflateEnd();
z.next_in = null;
z.next_out = null;
}
}

View File

@ -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.
*/
package io.netty.handler.codec.spdy;
import io.netty.buffer.ChannelBuffer;
import io.netty.handler.codec.compression.CompressionException;
import io.netty.util.internal.jzlib.JZlib;
import io.netty.util.internal.jzlib.ZStream;
import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
class SpdyHeaderBlockJZlibDecompressor extends SpdyHeaderBlockDecompressor {
private final byte[] out = new byte[8192];
private final ZStream z = new ZStream();
public SpdyHeaderBlockJZlibDecompressor() {
int resultCode;
resultCode = z.inflateInit(JZlib.W_ZLIB);
if (resultCode != JZlib.Z_OK) {
throw new CompressionException("ZStream initialization failure");
}
z.next_out = out;
}
@Override
public void setInput(ChannelBuffer compressed) {
byte[] in = new byte[compressed.readableBytes()];
compressed.readBytes(in);
z.next_in = in;
z.next_in_index = 0;
z.avail_in = in.length;
}
@Override
public void decode(ChannelBuffer decompressed) {
z.next_out_index = 0;
z.avail_out = out.length;
int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
if (resultCode == JZlib.Z_NEED_DICT) {
resultCode = z.inflateSetDictionary(SPDY_DICT, SPDY_DICT.length);
if (resultCode != JZlib.Z_OK) {
throw new CompressionException("ZStream dictionary failure");
}
z.inflate(JZlib.Z_SYNC_FLUSH);
}
if (z.next_out_index > 0) {
decompressed.writeBytes(out, 0, z.next_out_index);
}
}
}

View File

@ -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.
*/
package io.netty.handler.codec.spdy;
import java.util.zip.Deflater;
import io.netty.buffer.ChannelBuffer;
import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
class SpdyHeaderBlockZlibCompressor extends SpdyHeaderBlockCompressor {
private final byte[] out = new byte[8192];
private final Deflater compressor;
public SpdyHeaderBlockZlibCompressor(int compressionLevel) {
if (compressionLevel < 0 || compressionLevel > 9) {
throw new IllegalArgumentException(
"compressionLevel: " + compressionLevel + " (expected: 0-9)");
}
compressor = new Deflater(compressionLevel);
compressor.setDictionary(SPDY_DICT);
}
@Override
public void setInput(ChannelBuffer decompressed) {
byte[] in = new byte[decompressed.readableBytes()];
decompressed.readBytes(in);
compressor.setInput(in);
}
@Override
public void encode(ChannelBuffer compressed) {
while (!compressor.needsInput()) {
int numBytes = compressor.deflate(out, 0, out.length, Deflater.SYNC_FLUSH);
compressed.writeBytes(out, 0, numBytes);
}
}
@Override
public void end() {
compressor.end();
}
}

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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.HashMap;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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.handler.codec.http.HttpHeaders;

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,21 +13,6 @@
* 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;
/**

View File

@ -13,22 +13,6 @@
* 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.
*

View File

@ -13,21 +13,6 @@
* 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.*;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -13,21 +13,6 @@
* 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;

View File

@ -22,9 +22,11 @@ import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.Queue;
import io.netty.channel.Channels;
import io.netty.buffer.ChannelBufferFactory;
import io.netty.channel.Channel;
import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
@ -224,6 +226,16 @@ abstract class AbstractCodecEmbedder<E> implements CodecEmbedder<E> {
throw new CodecEmbedderException(actualCause);
}
@Override
public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) {
try {
task.run();
return Channels.succeededFuture(pipeline.getChannel());
} catch (Throwable t) {
return Channels.failedFuture(pipeline.getChannel(), t);
}
}
}
private static final class EmbeddedChannelPipeline extends DefaultChannelPipeline {

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.frame;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBufferFactory;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
@ -74,11 +75,13 @@ public class FixedLengthFrameDecoder extends FrameDecoder {
}
@Override
protected ChannelBuffer createCumulationDynamicBuffer(ChannelHandlerContext ctx) {
protected ChannelBuffer newCumulationBuffer(ChannelHandlerContext ctx, int minimumCapacity) {
ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory();
if (allocateFullBuffer) {
return ChannelBuffers.dynamicBuffer(frameLength, ctx.getChannel().getConfig().getBufferFactory());
return ChannelBuffers.dynamicBuffer(
factory.getDefaultOrder(), frameLength, ctx.getChannel().getConfig().getBufferFactory());
}
return super.createCumulationDynamicBuffer(ctx);
return super.newCumulationBuffer(ctx, minimumCapacity);
}
}

View File

@ -18,6 +18,7 @@ package io.netty.handler.codec.frame;
import java.net.SocketAddress;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBufferFactory;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
@ -206,25 +207,22 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
if (input.readable()) {
// seems like there is something readable left in the input buffer. So create the cumulation buffer and copy the input into it
ChannelBuffer cumulation = cumulation(ctx);
cumulation.writeBytes(input);
(this.cumulation = newCumulationBuffer(ctx, input.readableBytes())).writeBytes(input);
}
} else {
ChannelBuffer cumulation = cumulation(ctx);
if (cumulation.readable()) {
ChannelBuffer cumulation = this.cumulation;
assert cumulation.readable();
if (cumulation.writableBytes() < input.readableBytes()) {
cumulation.discardReadBytes();
}
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
} else {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
if (input.readable()) {
cumulation.writeBytes(input);
if (!cumulation.readable()) {
this.cumulation = null;
}
}
}
}
@Override
public void channelDisconnected(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
@ -303,10 +301,6 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler {
unfoldAndFireMessageReceived(context, remoteAddress, frame);
}
if (!cumulation.readable()) {
this.cumulation = null;
}
}
private void unfoldAndFireMessageReceived(ChannelHandlerContext context, SocketAddress remoteAddress, Object result) {
@ -333,10 +327,10 @@ public abstract class FrameDecoder extends SimpleChannelUpstreamHandler {
ChannelBuffer cumulation = this.cumulation;
if (cumulation == null) {
return;
} else {
this.cumulation = null;
}
this.cumulation = null;
if (cumulation.readable()) {
// Make sure all frames are read before notifying a closed channel.
callDecode(ctx, ctx.getChannel(), cumulation, null);
@ -355,28 +349,18 @@ 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 for cumulation
*/
private ChannelBuffer cumulation(ChannelHandlerContext ctx) {
ChannelBuffer c = cumulation;
if (c == null) {
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.
* 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
* pre-allocated 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());
protected ChannelBuffer newCumulationBuffer(
ChannelHandlerContext ctx, int minimumCapacity) {
ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory();
return ChannelBuffers.dynamicBuffer(
factory.getDefaultOrder(), Math.max(minimumCapacity, 256), factory);
}
}

View File

@ -289,7 +289,6 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
private ChannelBuffer cumulation;
private boolean needsCleanup;
private final boolean unfold;
private ReplayingDecoderBuffer replayable;
private T state;
@ -430,11 +429,58 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
return;
}
ChannelBuffer cumulation = cumulation(ctx);
needsCleanup = true;
cumulation.discardReadBytes();
if (cumulation == null) {
// the cumulation buffer is not created yet so just pass the input
// to callDecode(...) method
this.cumulation = input;
replayable = new ReplayingDecoderBuffer(input);
int oldReaderIndex = input.readerIndex();
int inputSize = input.readableBytes();
callDecode(
ctx, e.getChannel(),
input, replayable,
e.getRemoteAddress());
if (input.readable()) {
// seems like there is something readable left in the input buffer
// or decoder wants a replay - create the cumulation buffer and
// copy the input into it
ChannelBuffer cumulation;
if (checkpoint > 0) {
int bytesToPreserve = inputSize - (checkpoint - oldReaderIndex);
cumulation = this.cumulation =
newCumulationBuffer(ctx, bytesToPreserve);
cumulation.writeBytes(input, checkpoint, bytesToPreserve);
} else if (checkpoint == 0) {
cumulation = this.cumulation =
newCumulationBuffer(ctx, inputSize);
cumulation.writeBytes(input, oldReaderIndex, inputSize);
cumulation.readerIndex(input.readerIndex());
} else {
cumulation = this.cumulation =
newCumulationBuffer(ctx, input.readableBytes());
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
}
replayable = new ReplayingDecoderBuffer(cumulation);
} else {
this.cumulation = null;
replayable = ReplayingDecoderBuffer.EMPTY_BUFFER;
}
} else {
ChannelBuffer cumulation = this.cumulation;
assert cumulation.readable();
if (cumulation.writableBytes() < input.readableBytes()) {
cumulation.discardReadBytes();
}
cumulation.writeBytes(input);
callDecode(ctx, e.getChannel(), cumulation, replayable, e.getRemoteAddress());
if (!cumulation.readable()) {
this.cumulation = null;
replayable = ReplayingDecoderBuffer.EMPTY_BUFFER;
}
}
}
@Override
@ -455,15 +501,15 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
ctx.sendUpstream(e);
}
private void callDecode(ChannelHandlerContext context, Channel channel, ChannelBuffer cumulation, SocketAddress remoteAddress) throws Exception {
while (cumulation.readable()) {
int oldReaderIndex = checkpoint = cumulation.readerIndex();
private void callDecode(ChannelHandlerContext context, Channel channel, ChannelBuffer input, ChannelBuffer replayableInput, SocketAddress remoteAddress) throws Exception {
while (input.readable()) {
int oldReaderIndex = checkpoint = input.readerIndex();
Object result = null;
T oldState = state;
try {
result = decode(context, channel, replayable, state);
result = decode(context, channel, replayableInput, state);
if (result == null) {
if (oldReaderIndex == cumulation.readerIndex() && oldState == state) {
if (oldReaderIndex == input.readerIndex() && oldState == state) {
throw new IllegalStateException(
"null cannot be returned if no data is consumed and state didn't change.");
} else {
@ -476,7 +522,7 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
// Return to the checkpoint (or oldPosition) and retry.
int checkpoint = this.checkpoint;
if (checkpoint >= 0) {
cumulation.readerIndex(checkpoint);
input.readerIndex(checkpoint);
} else {
// Called by cleanup() - no need to maintain the readerIndex
// anymore because the buffer has been released already.
@ -489,7 +535,7 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
break;
}
if (oldReaderIndex == cumulation.readerIndex() && oldState == state) {
if (oldReaderIndex == input.readerIndex() && oldState == state) {
throw new IllegalStateException(
"decode() method must consume at least one byte " +
"if it returned a decoded message (caused by: " +
@ -498,11 +544,6 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
// A successful decode
unfoldAndFireMessageReceived(context, result, remoteAddress);
if (!cumulation.readable()) {
this.cumulation = null;
replayable = ReplayingDecoderBuffer.EMPTY_BUFFER;
}
}
}
@ -528,19 +569,17 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
private void cleanup(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
try {
if (!needsCleanup) {
ChannelBuffer cumulation = this.cumulation;
if (cumulation == null) {
return;
} else {
needsCleanup = false;
}
ChannelBuffer cumulation = this.cumulation;
this.cumulation = null;
replayable.terminate();
if (cumulation != null && cumulation.readable()) {
// Make sure all data was read before notifying a closed channel.
callDecode(ctx, e.getChannel(), cumulation, null);
callDecode(ctx, e.getChannel(), cumulation, replayable, null);
}
// Call decodeLast() finally. Please note that decodeLast() is
@ -558,19 +597,19 @@ public abstract class ReplayingDecoder<T extends Enum<T>>
}
}
private ChannelBuffer cumulation(ChannelHandlerContext ctx) {
ChannelBuffer buf = this.cumulation;
if (buf == null) {
if (cumulation == null) {
/**
* 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
* pre-allocated 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 newCumulationBuffer(
ChannelHandlerContext ctx, int minimumCapacity) {
ChannelBufferFactory factory = ctx.getChannel().getConfig().getBufferFactory();
buf = new UnsafeDynamicChannelBuffer(factory);
cumulation = buf;
replayable = new ReplayingDecoderBuffer(buf);
} else {
buf = cumulation;
}
}
return buf;
return ChannelBuffers.dynamicBuffer(
factory.getDefaultOrder(), Math.max(minimumCapacity, 256), factory);
}
}

View File

@ -612,6 +612,7 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
@SuppressWarnings("unchecked")
static <E> E cast(Object item) {
// assert item == null || item.getClass() != Node.class;
// Explicit cast, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
return (E) item;
}
@ -625,6 +626,7 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
* @return an item if matched, else e
* @throws NullPointerException if haveData mode but e is null
*/
@SuppressWarnings("unchecked")
private E xfer(E e, boolean haveData, int how, long nanos) {
if (haveData && e == null) {
throw new NullPointerException();
@ -653,7 +655,8 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
}
}
LockSupport.unpark(p.waiter);
return LegacyLinkedTransferQueue.cast(item);
// Explicit cast, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
return (E) LegacyLinkedTransferQueue.cast(item);
}
}
Node n = p.next;
@ -726,6 +729,7 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
* @param nanos timeout in nanosecs, used only if timed is true
* @return matched item, or e if unmatched on interrupt or timeout
*/
@SuppressWarnings("unchecked")
private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
long lastTime = timed ? System.nanoTime() : 0L;
Thread w = Thread.currentThread();
@ -737,7 +741,8 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
if (item != e) { // matched
// assert item != s;
s.forgetContents(); // avoid garbage
return LegacyLinkedTransferQueue.cast(item);
// Explicit cast, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
return (E) LegacyLinkedTransferQueue.cast(item);
}
if ((w.isInterrupted() || timed && nanos <= 0) &&
s.casItem(e, s)) { // cancel
@ -820,12 +825,14 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
* Returns the item in the first unmatched node with isData; or
* null if none. Used by peek.
*/
@SuppressWarnings("unchecked")
private E firstDataItem() {
for (Node p = head; p != null; p = succ(p)) {
Object item = p.item;
if (p.isData) {
if (item != null && item != p) {
return LegacyLinkedTransferQueue.cast(item);
// Explicit cast, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
return (E) LegacyLinkedTransferQueue.cast(item);
}
}
else if (item == null) {
@ -870,6 +877,7 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
/**
* Moves to next node after prev, or first node if prev null.
*/
@SuppressWarnings("unchecked")
private void advance(Node prev) {
lastPred = lastRet;
lastRet = prev;
@ -878,7 +886,8 @@ public class LegacyLinkedTransferQueue<E> extends AbstractQueue<E>
Object item = p.item;
if (p.isData) {
if (item != null && item != p) {
nextItem = LegacyLinkedTransferQueue.cast(item);
// Explicit cast, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
nextItem = (E) LegacyLinkedTransferQueue.cast(item);
nextNode = p;
return;
}

View File

@ -81,6 +81,7 @@ import java.util.concurrent.locks.LockSupport;
* @param <E> the type of elements held in this collection
*/
@SuppressWarnings("restriction")
public class LinkedTransferQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
private static final long serialVersionUID = -3223113410248163686L;
@ -529,8 +530,6 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
return false;
}
private static final long serialVersionUID = -3375979862319811754L;
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long itemOffset;

View File

@ -112,4 +112,8 @@ final class Adler32 {
}
return s2 << 16 | s1;
}
private Adler32() {
// Utility Class
}
}

View File

@ -92,4 +92,8 @@ final class CRC32 {
crc32 ^= 0xffffffff;
return crc32;
}
private CRC32() {
// Utility Class
}
}

View File

@ -514,7 +514,7 @@ final class Deflate {
private void send_code(int c, short[] tree) {
int c2 = c * 2;
send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff));
send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
}
private void send_bits(int value, int length) {

View File

@ -124,16 +124,15 @@ final class InfBlocks {
int m; // bytes to end of window or read pointer
// copy input/output information to locals (UPDATE macro restores)
{
p = z.next_in_index;
n = z.avail_in;
b = bitb;
k = bitk;
}
{
q = write;
m = q < read? read - q - 1 : end - q;
}
// process input based on current state
while (true) {
@ -161,20 +160,17 @@ final class InfBlocks {
switch (t >>> 1) {
case 0: // stored
{
b >>>= 3;
k -= 3;
}
t = k & 7; // go to byte boundary
{
b >>>= t;
k -= t;
}
mode = LENS; // get length of stored block
break;
case 1: // fixed
{
int[] bl = new int[1];
int[] bd = new int[1];
int[][] tl = new int[1][];
@ -182,30 +178,24 @@ final class InfBlocks {
InfTree.inflate_trees_fixed(bl, bd, tl, td);
codes.init(bl[0], bd[0], tl[0], 0, td[0], 0);
}
{
b >>>= 3;
k -= 3;
}
mode = CODES;
break;
case 2: // dynamic
{
b >>>= 3;
k -= 3;
}
mode = TABLE;
break;
case 3: // illegal
{
b >>>= 3;
k -= 3;
}
mode = BAD;
z.msg = "invalid block type";
r = JZlib.Z_DATA_ERROR;
@ -352,10 +342,9 @@ final class InfBlocks {
}
}
{
b >>>= 14;
k -= 14;
}
index = 0;
mode = BTREE;
@ -380,10 +369,9 @@ final class InfBlocks {
blens[border[index ++]] = b & 7;
{
b >>>= 3;
k -= 3;
}
}
while (index < 19) {
@ -505,7 +493,7 @@ final class InfBlocks {
}
tb[0] = -1;
{
int[] bl = new int[1];
int[] bd = new int[1];
int[] tl = new int[1];
@ -534,7 +522,7 @@ final class InfBlocks {
return inflate_flush(z, r);
}
codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0]);
}
mode = CODES;
case CODES:
bitb = b;

View File

@ -71,7 +71,7 @@ final class InfCodes {
// mode dependent information
private int len;
private int[] tree; // pointer into tree
private int tree_index = 0;
private int tree_index;
private int need; // bits needed
private int lit;
// if EXT or COPY, where and how much

View File

@ -105,4 +105,8 @@ public final class JZlib {
enum WrapperType {
NONE, ZLIB, GZIP, ZLIB_OR_NONE
}
private JZlib() {
// Utility class
}
}

View File

@ -13,19 +13,9 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.replay;
import io.netty.buffer.ChannelBufferFactory;
import io.netty.buffer.DynamicChannelBuffer;
class UnsafeDynamicChannelBuffer extends DynamicChannelBuffer {
UnsafeDynamicChannelBuffer(ChannelBufferFactory factory) {
super(factory.getDefaultOrder(), 256, factory);
}
@Override
protected void checkReadableBytes(int minReaderRemaining) {
// Do not check here - ReplayingDecoderBuffer will check.
}
}
/**
* <em>Internal-use-only</em> utilities which is not allowed to be used
* outside Netty.
*/
package io.netty.util.internal.jzlib;

View File

@ -22,15 +22,12 @@ import io.netty.channel.ChannelPipelineFactory;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.logging.InternalLogLevel;
public class HttpSnoopServerPipelineFactory implements ChannelPipelineFactory {
@Override
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
pipeline.addLast("log", new LoggingHandler(InternalLogLevel.INFO));
// Uncomment the following line if you want HTTPS
//SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();

View File

@ -17,9 +17,6 @@ package io.netty.example.http.websocketx.autobahn;
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;

View File

@ -17,9 +17,6 @@ package io.netty.example.http.websocketx.server;
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;

View File

@ -17,9 +17,6 @@ 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;

View File

@ -87,7 +87,6 @@ public class SctpClient {
// Parse options.
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final int firstMessageSize;
new SctpClient(host, port).run();
}

View File

@ -45,7 +45,7 @@ public class SecureChatClientPipelineFactory implements
SSLEngine engine =
SecureChatSslContextFactory.getClientContext().createSSLEngine();
//engine.setUseClientMode(true);
engine.setUseClientMode(true);
pipeline.addLast("ssl", new SslHandler(engine));

View File

@ -110,25 +110,40 @@ public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstre
private final Executor executor;
private final boolean handleDownstream;
private final boolean handleUpstream;
/**
* Creates a new instance with the specified {@link Executor}.
* Creates a new instance with the specified {@link Executor} which only handles upstream events.
* Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure.
*/
public ExecutionHandler(Executor executor) {
this(executor, false);
this(executor, false, true);
}
/**
* Use {@link #ExecutionHandler(Executor, boolean, boolean)}
*
* {@link Deprecated}
*/
@Deprecated
public ExecutionHandler(Executor executor, boolean handleDownstream) {
this(executor, handleDownstream, true);
}
/**
* Creates a new instance with the specified {@link Executor}.
* Specify an {@link OrderedMemoryAwareThreadPoolExecutor} if unsure.
*/
public ExecutionHandler(Executor executor, boolean handleDownstream) {
public ExecutionHandler(Executor executor, boolean handleDownstream, boolean handleUpstream) {
if (executor == null) {
throw new NullPointerException("executor");
}
if (!handleDownstream && !handleUpstream) {
throw new IllegalArgumentException("You must handle at least handle one event type");
}
this.executor = executor;
this.handleDownstream = handleDownstream;
this.handleUpstream = handleUpstream;
}
/**
@ -154,7 +169,11 @@ public class ExecutionHandler implements ChannelUpstreamHandler, ChannelDownstre
@Override
public void handleUpstream(
ChannelHandlerContext context, ChannelEvent e) throws Exception {
if (handleUpstream) {
executor.execute(new ChannelUpstreamEventRunnable(context, e));
} else {
context.sendUpstream(e);
}
}
@Override

View File

@ -419,11 +419,19 @@ public class MemoryAwareThreadPoolExecutor extends ThreadPoolExecutor {
//System.out.println("READABLE");
ChannelHandlerContext ctx = eventTask.getContext();
if (ctx.getHandler() instanceof ExecutionHandler) {
// check if the attachment was set as this means that we suspend the channel from reads. This only works when
// this pool is used with ExecutionHandler but I guess thats good enough for us.
//
// See #215
if (ctx.getAttachment() != null) {
// readSuspended = false;
ctx.setAttachment(null);
}
channel.setReadable(true);
}
} else {
channel.setReadable(true);
}
}
}
}
}

View File

@ -0,0 +1,165 @@
/*
* 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.Channel;
import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* {@link Executor} which should be used for downstream {@link ChannelEvent}'s. This implementation will take care of preserve the order of the events in a {@link Channel}.
* If you don't need to preserve the order just use one of the {@link Executor} implementations provided by the static methods of {@link Executors}.
* <br>
* <br>
*
* For more informations about how the order is preserved see {@link OrderedMemoryAwareThreadPoolExecutor}
*
*/
public final class OrderedDownstreamThreadPoolExecutor extends OrderedMemoryAwareThreadPoolExecutor {
/**
* Creates a new instance.
*
* @param corePoolSize the maximum number of active threads
*/
public OrderedDownstreamThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, 0L, 0L);
}
/**
* Creates a new instance.
*
* @param corePoolSize the maximum number of active threads
* @param keepAliveTime the amount of time for an inactive thread to shut itself down
* @param unit the {@link TimeUnit} of {@code keepAliveTime}
*/
public OrderedDownstreamThreadPoolExecutor(
int corePoolSize, long keepAliveTime, TimeUnit unit) {
super(corePoolSize, 0L, 0L, keepAliveTime, unit);
}
/**
* Creates a new instance.
*
* @param corePoolSize the maximum number of active threads
* @param keepAliveTime the amount of time for an inactive thread to shut itself down
* @param unit the {@link TimeUnit} of {@code keepAliveTime}
* @param threadFactory the {@link ThreadFactory} of this pool
*/
public OrderedDownstreamThreadPoolExecutor(
int corePoolSize, long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) {
super(corePoolSize, 0L, 0L,
keepAliveTime, unit, threadFactory);
}
/**
* Return <code>null</code>
*/
@Override
public ObjectSizeEstimator getObjectSizeEstimator() {
return null;
}
/**
* Throws {@link UnsupportedOperationException} as there is not support for limit the memory size in this implementation
*/
@Override
public void setObjectSizeEstimator(ObjectSizeEstimator objectSizeEstimator) {
throw new UnsupportedOperationException("Not supported by this implementation");
}
/**
* Returns <code>0L</code>
*/
@Override
public long getMaxChannelMemorySize() {
return 0L;
}
/**
* Throws {@link UnsupportedOperationException} as there is not support for limit the memory size in this implementation
*/
@Override
public void setMaxChannelMemorySize(long maxChannelMemorySize) {
throw new UnsupportedOperationException("Not supported by this implementation");
}
/**
* Returns <code>0L</code>
*/
@Override
public long getMaxTotalMemorySize() {
return 0L;
}
/**
* Throws {@link UnsupportedOperationException} as there is not support for limit the memory size in this implementation
*/
@Override
public void setMaxTotalMemorySize(long maxTotalMemorySize) {
throw new UnsupportedOperationException("Not supported by this implementation");
}
/**
* Return <code>false</code> as we not need to cound the memory in this implementation
*/
@Override
protected boolean shouldCount(Runnable task) {
return false;
}
@Override
public void execute(Runnable command) {
// check if the Runnable was of an unsupported type
if (command instanceof ChannelUpstreamEventRunnable) {
throw new RejectedExecutionException("command must be enclosed with an downstream event.");
}
doExecute(command);
}
@Override
protected Executor getChildExecutor(ChannelEvent e) {
final Object key = getChildExecutorKey(e);
Executor executor = childExecutors.get(key);
if (executor == null) {
executor = new ChildExecutor();
Executor oldExecutor = childExecutors.putIfAbsent(key, executor);
if (oldExecutor != null) {
executor = oldExecutor;
} else {
// register a listener so that the ChildExecutor will get removed once the channel was closed
e.getChannel().getCloseFuture().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
removeChildExecutor(key);
}
});
}
}
return executor;
}
}

View File

@ -136,7 +136,7 @@ public class OrderedMemoryAwareThreadPoolExecutor extends
// TODO Make OMATPE focus on the case where Channel is the key.
// Add a new less-efficient TPE that allows custom key.
private final ConcurrentMap<Object, Executor> childExecutors = newChildExecutorMap();
protected final ConcurrentMap<Object, Executor> childExecutors = newChildExecutorMap();
/**
* Creates a new instance.
@ -242,7 +242,7 @@ public class OrderedMemoryAwareThreadPoolExecutor extends
}
}
private Executor getChildExecutor(ChannelEvent e) {
protected Executor getChildExecutor(ChannelEvent e) {
Object key = getChildExecutorKey(e);
Executor executor = childExecutors.get(key);
if (executor == null) {
@ -278,7 +278,7 @@ public class OrderedMemoryAwareThreadPoolExecutor extends
afterExecute(r, t);
}
private final class ChildExecutor implements Executor, Runnable {
protected final class ChildExecutor implements Executor, Runnable {
private final Queue<Runnable> tasks = QueueFactory.createQueue(Runnable.class);
private final AtomicBoolean isRunning = new AtomicBoolean();

View File

@ -574,15 +574,15 @@ public class SslHandler extends FrameDecoder
if (tls) {
// SSLv3 or TLS - Check ProtocolVersion
int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + 1);
if (majorVersion >= 3 && majorVersion < 10) {
if (majorVersion == 3) {
// SSLv3 or TLS
packetLength = (getShort(buffer, buffer.readerIndex() + 3) & 0xFFFF) + 5;
if (packetLength <= 5) {
// Neither SSLv2 or TLSv1 (i.e. SSLv2 or bad data)
// Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
tls = false;
}
} else {
// Neither SSLv2 or TLSv1 (i.e. SSLv2 or bad data)
// Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
tls = false;
}
}
@ -594,7 +594,7 @@ public class SslHandler extends FrameDecoder
buffer.readerIndex()) & 0x80) != 0 ? 2 : 3;
int majorVersion = buffer.getUnsignedByte(
buffer.readerIndex() + headerLength + 1);
if (majorVersion >= 2 && majorVersion < 10) {
if (majorVersion == 2 || majorVersion == 3) {
// SSLv2
if (headerLength == 2) {
packetLength = (getShort(buffer, buffer.readerIndex()) & 0x7FFF) + 2;
@ -972,7 +972,7 @@ public class SslHandler extends FrameDecoder
outAppBuf.flip();
if (outAppBuf.hasRemaining()) {
ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining());
ChannelBuffer frame = ctx.getChannel().getConfig().getBufferFactory().getBuffer(outAppBuf.remaining());
frame.writeBytes(outAppBuf.array(), 0, frame.capacity());
return frame;
} else {

View File

@ -90,7 +90,7 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
}
try {
flush(ctx);
flush(ctx, false);
} catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("Unexpected exception while sending chunks.", e);
@ -112,10 +112,10 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
final Channel channel = ctx.getChannel();
if (channel.isWritable()) {
this.ctx = ctx;
flush(ctx);
flush(ctx, false);
} else if (!channel.isConnected()) {
this.ctx = ctx;
discard(ctx);
discard(ctx, false);
}
}
@ -127,12 +127,12 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
switch (cse.getState()) {
case INTEREST_OPS:
// Continue writing when the channel becomes writable.
flush(ctx);
flush(ctx, true);
break;
case OPEN:
if (!Boolean.TRUE.equals(cse.getValue())) {
// Fail all pending writes
discard(ctx);
discard(ctx, true);
}
break;
}
@ -140,7 +140,7 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
ctx.sendUpstream(e);
}
private void discard(ChannelHandlerContext ctx) {
private void discard(ChannelHandlerContext ctx, boolean fireNow) {
ClosedChannelException cause = null;
boolean fireExceptionCaught = false;
@ -169,20 +169,22 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
}
currentEvent.getFuture().setFailure(cause);
fireExceptionCaught = true;
currentEvent = null;
}
if (fireExceptionCaught) {
Channels.fireExceptionCaught(ctx.getChannel(), cause);
if (fireNow) {
fireExceptionCaught(ctx, cause);
} else {
fireExceptionCaughtLater(ctx, cause);
}
}
}
private synchronized void flush(ChannelHandlerContext ctx) throws Exception {
private synchronized void flush(ChannelHandlerContext ctx, boolean fireNow) throws Exception {
final Channel channel = ctx.getChannel();
if (!channel.isConnected()) {
discard(ctx);
discard(ctx, fireNow);
}
while (channel.isWritable()) {
@ -220,7 +222,11 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
this.currentEvent = null;
currentEvent.getFuture().setFailure(t);
if (fireNow) {
fireExceptionCaught(ctx, t);
} else {
fireExceptionCaughtLater(ctx, t);
}
closeInput(chunks);
break;
@ -262,7 +268,7 @@ public class ChunkedWriteHandler implements ChannelUpstreamHandler, ChannelDowns
}
if (!channel.isConnected()) {
discard(ctx);
discard(ctx, fireNow);
break;
}
}

View File

@ -154,7 +154,7 @@ public class WriteTimeoutHandler extends SimpleChannelDownstreamHandler
}
protected void writeTimedOut(ChannelHandlerContext ctx) throws Exception {
Channels.fireExceptionCaught(ctx, EXCEPTION);
Channels.fireExceptionCaughtLater(ctx, EXCEPTION);
}
private final class WriteTimeoutTask implements TimerTask {

Binary file not shown.

48
pom.xml
View File

@ -212,12 +212,12 @@
<configuration>
<rules>
<requireJavaVersion>
<!-- Enforce java 1.6 as minimum for compiling -->
<!-- This is needed because of the Unsafe detection code -->
<version>[1.6.0,)</version>
<!-- Enforce java 1.7 as minimum for compiling -->
<!-- This is needed because of java.util.zip.Deflater -->
<version>[1.7.0,)</version>
</requireJavaVersion>
<requireMavenVersion>
<version>[3.0.3,)</version>
<version>[3.0.2,)</version>
</requireMavenVersion>
</rules>
</configuration>
@ -237,6 +237,32 @@
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<!-- ensure that only methods available in java 1.6 can
be used even when compiling with java 1.7+ -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java16</artifactId>
<version>1.0</version>
</signature>
<ignores>
<ignore>sun.misc.Unsafe</ignore>
<ignore>java.util.zip.Deflater</ignore>
</ignores>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.8</version>
@ -260,10 +286,22 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-build</artifactId>
<version>6</version>
<version>7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<forkMode>once</forkMode>
<excludes>
<exclude>**/Abstract*</exclude>
<exclude>**/TestUtil*</exclude>
</excludes>
<runOrder>random</runOrder>
</configuration>
</plugin>
</plugins>
<!-- Workaround for the 'M2E plugin execution not covered' problem.

View File

@ -35,6 +35,14 @@
<artifactId>netty-codec-http</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Servlet API - completely optional -->
<!-- Used for HTTP tunneling transport -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,248 @@
/*
* 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.http;
import java.io.EOFException;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.net.SocketAddress;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.Channels;
import io.netty.channel.ExceptionEvent;
import io.netty.channel.MessageEvent;
import io.netty.channel.SimpleChannelUpstreamHandler;
import io.netty.channel.local.DefaultLocalClientChannelFactory;
import io.netty.channel.local.LocalAddress;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
/**
* An {@link HttpServlet} that proxies an incoming data to the actual server
* and vice versa. Please refer to the
* <a href="package-summary.html#package_description">package summary</a> for
* the detailed usage.
* @apiviz.landmark
*/
public class HttpTunnelingServlet extends HttpServlet {
private static final long serialVersionUID = 4259910275899756070L;
private static final String ENDPOINT = "endpoint";
static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpTunnelingServlet.class);
private volatile SocketAddress remoteAddress;
private volatile ChannelFactory channelFactory;
@Override
public void init() throws ServletException {
ServletConfig config = getServletConfig();
String endpoint = config.getInitParameter(ENDPOINT);
if (endpoint == null) {
throw new ServletException("init-param '" + ENDPOINT + "' must be specified.");
}
try {
remoteAddress = parseEndpoint(endpoint.trim());
} catch (ServletException e) {
throw e;
} catch (Exception e) {
throw new ServletException("Failed to parse an endpoint.", e);
}
try {
channelFactory = createChannelFactory(remoteAddress);
} catch (ServletException e) {
throw e;
} catch (Exception e) {
throw new ServletException("Failed to create a channel factory.", e);
}
// Stuff for testing purpose
//ServerBootstrap b = new ServerBootstrap(new DefaultLocalServerChannelFactory());
//b.getPipeline().addLast("logger", new LoggingHandler(getClass(), InternalLogLevel.INFO, true));
//b.getPipeline().addLast("handler", new EchoHandler());
//b.bind(remoteAddress);
}
protected SocketAddress parseEndpoint(String endpoint) throws Exception {
if (endpoint.startsWith("local:")) {
return new LocalAddress(endpoint.substring(6).trim());
} else {
throw new ServletException(
"Invalid or unknown endpoint: " + endpoint);
}
}
protected ChannelFactory createChannelFactory(SocketAddress remoteAddress) throws Exception {
if (remoteAddress instanceof LocalAddress) {
return new DefaultLocalClientChannelFactory();
} else {
throw new ServletException(
"Unsupported remote address type: " +
remoteAddress.getClass().getName());
}
}
@Override
public void destroy() {
try {
destroyChannelFactory(channelFactory);
} catch (Exception e) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to destroy a channel factory.", e);
}
}
}
protected void destroyChannelFactory(ChannelFactory factory) throws Exception {
factory.releaseExternalResources();
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
if (!"POST".equalsIgnoreCase(req.getMethod())) {
if (logger.isWarnEnabled()) {
logger.warn("Unallowed method: " + req.getMethod());
}
res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
return;
}
final ChannelPipeline pipeline = Channels.pipeline();
final ServletOutputStream out = res.getOutputStream();
final OutboundConnectionHandler handler = new OutboundConnectionHandler(out);
pipeline.addLast("handler", handler);
Channel channel = channelFactory.newChannel(pipeline);
ChannelFuture future = channel.connect(remoteAddress).awaitUninterruptibly();
if (!future.isSuccess()) {
Throwable cause = future.getCause();
if (logger.isWarnEnabled()) {
logger.warn("Endpoint unavailable: " + cause.getMessage(), cause);
}
res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
return;
}
ChannelFuture lastWriteFuture = null;
try {
res.setStatus(HttpServletResponse.SC_OK);
res.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
res.setHeader(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY);
// Initiate chunked encoding by flushing the headers.
out.flush();
PushbackInputStream in =
new PushbackInputStream(req.getInputStream());
while (channel.isConnected()) {
ChannelBuffer buffer;
try {
buffer = read(in);
} catch (EOFException e) {
break;
}
if (buffer == null) {
break;
}
lastWriteFuture = channel.write(buffer);
}
} finally {
if (lastWriteFuture == null) {
channel.close();
} else {
lastWriteFuture.addListener(ChannelFutureListener.CLOSE);
}
}
}
private static ChannelBuffer read(PushbackInputStream in) throws IOException {
byte[] buf;
int readBytes;
int bytesToRead = in.available();
if (bytesToRead > 0) {
buf = new byte[bytesToRead];
readBytes = in.read(buf);
} else if (bytesToRead == 0) {
int b = in.read();
if (b < 0 || in.available() < 0) {
return null;
}
in.unread(b);
bytesToRead = in.available();
buf = new byte[bytesToRead];
readBytes = in.read(buf);
} else {
return null;
}
assert readBytes > 0;
ChannelBuffer buffer;
if (readBytes == buf.length) {
buffer = ChannelBuffers.wrappedBuffer(buf);
} else {
// A rare case, but it sometimes happen.
buffer = ChannelBuffers.wrappedBuffer(buf, 0, readBytes);
}
return buffer;
}
private static final class OutboundConnectionHandler extends SimpleChannelUpstreamHandler {
private final ServletOutputStream out;
public OutboundConnectionHandler(ServletOutputStream out) {
this.out = out;
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
synchronized (this) {
buffer.readBytes(out, buffer.readableBytes());
out.flush();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
if (logger.isWarnEnabled()) {
logger.warn("Unexpected exception while HTTP tunneling", e.getCause());
}
e.getChannel().close();
}
}
}

View File

@ -52,4 +52,6 @@ public abstract class SctpChannel extends AbstractSelectableChannel {
public abstract <T> MessageInfo receive(ByteBuffer dst, T attachment, NotificationHandler<T> handler) throws IOException;
public abstract int send(ByteBuffer src, MessageInfo messageInfo) throws IOException;
public abstract Set<SctpSocketOption<?>> supportedOptions();
}

View File

@ -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 io.netty.channel.sctp;
import io.netty.channel.AbstractChannelSink;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPipeline;
public abstract class AbstractSctpChannelSink extends AbstractChannelSink {
@Override
public ChannelFuture execute(ChannelPipeline pipeline, final Runnable task) {
Channel ch = pipeline.getChannel();
if (ch instanceof SctpChannelImpl) {
SctpChannelImpl channel = (SctpChannelImpl) ch;
return channel.worker.executeInIoThread(channel, task);
} else {
return super.execute(pipeline, task);
}
}
}

View File

@ -17,7 +17,6 @@ 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.sctp.SctpChannelConfig} for a NIO SCTP/IP {@link io.netty.channel.sctp.SctpChannel}.

View File

@ -18,9 +18,6 @@ package io.netty.channel.sctp;
import com.sun.nio.sctp.Association;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.SocketChannelConfig;
import io.netty.channel.socket.nio.NioSocketChannelConfig;
import java.net.InetAddress;
import java.net.InetSocketAddress;

View File

@ -257,8 +257,6 @@ class SctpChannelImpl extends AbstractChannel implements SctpChannel {
private final class WriteRequestQueue extends AbstractWriteRequestQueue {
private static final long serialVersionUID = -246694024103520626L;
private final ThreadLocalBoolean notifying = new ThreadLocalBoolean();
WriteRequestQueue() {

View File

@ -32,7 +32,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.channel.AbstractChannelSink;
import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelException;
import io.netty.channel.ChannelFuture;
@ -48,7 +47,7 @@ import io.netty.util.internal.QueueFactory;
/**
*/
class SctpClientPipelineSink extends AbstractChannelSink {
class SctpClientPipelineSink extends AbstractSctpChannelSink {
static final InternalLogger logger =
InternalLoggerFactory.getInstance(SctpClientPipelineSink.class);
@ -262,7 +261,7 @@ class SctpClientPipelineSink extends AbstractChannelSink {
wakenUp.set(false);
try {
int selectedKeyCount = selector.select(500);
int selectedKeyCount = selector.select(10);
// 'wakenUp.compareAndSet(false, true)' is always evaluated
// before calling 'selector.wakeup()' to reduce the wake-up
@ -302,9 +301,9 @@ class SctpClientPipelineSink extends AbstractChannelSink {
processSelectedKeys(selector.selectedKeys());
}
// Handle connection timeout every 0.5 seconds approximately.
// Handle connection timeout every 10 milliseconds approximately.
long currentTimeNanos = System.nanoTime();
if (currentTimeNanos - lastConnectTimeoutCheckTimeNanos >= 500 * 1000000L) {
if (currentTimeNanos - lastConnectTimeoutCheckTimeNanos >= 10 * 1000000L) {
lastConnectTimeoutCheckTimeNanos = currentTimeNanos;
processConnectTimeout(selector.keys(), currentTimeNanos);
}

View File

@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicInteger;
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;
@ -45,7 +44,7 @@ import io.netty.util.internal.DeadLockProofWorker;
/**
*/
class SctpServerPipelineSink extends AbstractChannelSink {
class SctpServerPipelineSink extends AbstractSctpChannelSink {
static final InternalLogger logger =
InternalLoggerFactory.getInstance(SctpServerPipelineSink.class);

View File

@ -31,6 +31,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@ -45,6 +46,8 @@ 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.channel.socket.ChannelRunnableWrapper;
import io.netty.channel.socket.Worker;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.util.internal.DeadLockProofWorker;
@ -53,7 +56,7 @@ import io.netty.util.internal.QueueFactory;
/**
*/
@SuppressWarnings("unchecked")
class SctpWorker implements Runnable {
class SctpWorker implements Worker {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(SctpWorker.class);
@ -64,13 +67,15 @@ class SctpWorker implements Runnable {
private final Executor executor;
private boolean started;
private volatile Thread thread;
volatile Thread thread;
volatile Selector selector;
private final AtomicBoolean wakenUp = new AtomicBoolean();
private final ReadWriteLock selectorGuard = new ReentrantReadWriteLock();
private final Object startStopLock = new Object();
private final Queue<Runnable> registerTaskQueue = QueueFactory.createQueue(Runnable.class);
private final Queue<Runnable> writeTaskQueue = QueueFactory.createQueue(Runnable.class);
private final Queue<Runnable> eventQueue = QueueFactory.createQueue(Runnable.class);
private volatile int cancelledKeys; // should use AtomicInteger but we just need approximation
private final SctpReceiveBufferPool recvBufferPool = new SctpReceiveBufferPool();
@ -188,6 +193,7 @@ class SctpWorker implements Runnable {
cancelledKeys = 0;
processRegisterTaskQueue();
processEventQueue();
processWriteTaskQueue();
processSelectedKeys(selector.selectedKeys());
@ -241,6 +247,34 @@ class SctpWorker implements Runnable {
}
}
@Override
public ChannelFuture executeInIoThread(Channel channel, Runnable task) {
if (channel instanceof SctpChannelImpl && isIoThread((SctpChannelImpl) channel)) {
try {
task.run();
return succeededFuture(channel);
} catch (Throwable t) {
return failedFuture(channel, t);
}
} else {
ChannelRunnableWrapper channelRunnable = new ChannelRunnableWrapper(channel, task);
boolean added = eventQueue.offer(channelRunnable);
if (added) {
// wake up the selector to speed things
selector.wakeup();
} else {
channelRunnable.setFailure(new RejectedExecutionException("Unable to queue task " + task));
}
return channelRunnable;
}
}
static boolean isIoThread(SctpChannelImpl channel) {
return Thread.currentThread() == channel.worker.thread;
}
private void processRegisterTaskQueue() throws IOException {
for (; ;) {
final Runnable task = registerTaskQueue.poll();
@ -265,6 +299,17 @@ class SctpWorker implements Runnable {
}
}
private void processEventQueue() throws IOException {
for (;;) {
final Runnable task = eventQueue.poll();
if (task == null) {
break;
}
task.run();
cleanUpCancelledKeys();
}
}
private void processSelectedKeys(final Set<SelectionKey> selectedKeys) throws IOException {
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
SelectionKey k = i.next();

View File

@ -19,8 +19,6 @@ import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelHandler;
import io.netty.channel.sctp.SctpNotificationEvent;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
/**
* SCTP Channel Handler (upstream + downstream) with SCTP notification handling
@ -28,10 +26,6 @@ import io.netty.logging.InternalLoggerFactory;
public class SimpleSctpChannelHandler extends SimpleChannelHandler {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(SimpleSctpUpstreamHandler.class.getName());
@Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent event) throws Exception {
if (!(event instanceof SctpNotificationEvent)) {

View File

@ -19,16 +19,11 @@ import io.netty.channel.ChannelEvent;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelUpstreamHandler;
import io.netty.channel.sctp.SctpNotificationEvent;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
/**
* SCTP Upstream Channel Handler with SCTP notification handling
*/
public class SimpleSctpUpstreamHandler extends SimpleChannelUpstreamHandler {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(SimpleSctpUpstreamHandler.class.getName());
@Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent event) throws Exception {

View File

@ -15,7 +15,6 @@
*/
package io.netty.testsuite.transport;
import com.sun.nio.sctp.SctpChannel;
import com.sun.nio.sctp.SctpServerChannel;
import io.netty.bootstrap.ClientBootstrap;
import io.netty.channel.ChannelFactory;
@ -40,7 +39,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

View File

@ -23,8 +23,6 @@ import io.netty.channel.*;
import io.netty.channel.sctp.SctpClientSocketChannelFactory;
import io.netty.channel.sctp.SctpFrame;
import io.netty.channel.sctp.SctpServerSocketChannelFactory;
import io.netty.channel.sctp.codec.SctpFrameDecoder;
import io.netty.channel.sctp.codec.SctpFrameEncoder;
import io.netty.testsuite.util.SctpSocketAddresses;
import io.netty.util.internal.ExecutorUtil;
import org.junit.AfterClass;

View File

@ -16,7 +16,6 @@
package io.netty.testsuite.transport.sctp;
import io.netty.channel.ChannelFactory;
import io.netty.channel.sctp.SctpClientSocketChannelFactory;
import io.netty.channel.sctp.SctpServerSocketChannelFactory;
import io.netty.testsuite.transport.AbstractSocketServerBootstrapTest;

View File

@ -43,7 +43,28 @@ public abstract class AbstractChannelSink implements ChannelSink {
if (actualCause == null) {
actualCause = cause;
}
if (isFireExceptionCaughtLater(event, actualCause)) {
fireExceptionCaughtLater(event.getChannel(), actualCause);
} else {
fireExceptionCaught(event.getChannel(), actualCause);
}
}
protected boolean isFireExceptionCaughtLater(ChannelEvent event, Throwable actualCause) {
return false;
}
/**
* This implementation just directly call {@link Runnable#run()}. Sub-classes should override this if they can handle it
* in a better way
*/
@Override
public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) {
try {
task.run();
return Channels.succeededFuture(pipeline.getChannel());
} catch (Throwable t) {
return Channels.failedFuture(pipeline.getChannel(), t);
}
}
}

View File

@ -56,6 +56,10 @@ package io.netty.channel;
* <p>
* You will also find various helper methods in {@link Channels} to be useful
* to generate and send an artificial or manipulated event.
* <p>
* <strong>Caution:</strong>
* <p>
* Use the *Later(..) methods of the {@link Channels} class if you want to send an upstream event from a {@link ChannelDownstreamHandler} otherwise you may run into threading issues.
*
* <h3>State management</h3>
*

View File

@ -432,7 +432,6 @@ public interface ChannelPipeline {
*/
ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType);
/**
* Sends the specified {@link ChannelEvent} to the first
* {@link ChannelUpstreamHandler} in this pipeline.
@ -451,6 +450,12 @@ public interface ChannelPipeline {
*/
void sendDownstream(ChannelEvent e);
/**
* Schedules the specified task to be executed in the I/O thread associated
* with this pipeline's {@link Channel}.
*/
ChannelFuture execute(Runnable task);
/**
* Returns the {@link Channel} that this pipeline is attached to.
*

View File

@ -37,4 +37,10 @@ public interface ChannelSink {
* one of its {@link ChannelHandler}s process a {@link ChannelEvent}.
*/
void exceptionCaught(ChannelPipeline pipeline, ChannelEvent e, ChannelPipelineException cause) throws Exception;
/**
* Execute the given {@link Runnable} later in the io-thread.
* Some implementation may not support this and just execute it directly.
*/
ChannelFuture execute(ChannelPipeline pipeline, Runnable task);
}

View File

@ -298,6 +298,22 @@ public final class Channels {
ctx.getChannel(), message, remoteAddress));
}
/**
* Sends a {@code "writeComplete"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} in the next io-thread.
*/
public static ChannelFuture fireWriteCompleteLater(final Channel channel, final long amount) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireWriteComplete(channel, amount);
}
});
}
/**
* Sends a {@code "writeComplete"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -321,6 +337,25 @@ public final class Channels {
public static void fireWriteComplete(ChannelHandlerContext ctx, long amount) {
ctx.sendUpstream(new DefaultWriteCompletionEvent(ctx.getChannel(), amount));
}
/**
* Sends a {@code "channelInterestChanged"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} once the io-thread runs again.
*/
public static ChannelFuture fireChannelInterestChangedLater(final Channel channel) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireChannelInterestChanged(channel);
}
});
}
/**
* Sends a {@code "channelInterestChanged"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -346,6 +381,21 @@ public final class Channels {
ctx.getChannel(), ChannelState.INTEREST_OPS, Channel.OP_READ));
}
/**
* Sends a {@code "channelDisconnected"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} once the io-thread runs again.
*/
public static ChannelFuture fireChannelDisconnectedLater(final Channel channel) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireChannelDisconnected(channel);
}
});
}
/**
* Sends a {@code "channelDisconnected"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -368,6 +418,23 @@ public final class Channels {
ctx.getChannel(), ChannelState.CONNECTED, null));
}
/**
* Sends a {@code "channelUnbound"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} once the io-thread runs again.
*/
public static ChannelFuture fireChannelUnboundLater(final Channel channel) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireChannelUnbound(channel);
}
});
}
/**
* Sends a {@code "channelUnbound"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -390,6 +457,24 @@ public final class Channels {
ctx.getChannel(), ChannelState.BOUND, null));
}
/**
* Sends a {@code "channelClosed"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} once the io-thread runs again.
*/
public static ChannelFuture fireChannelClosedLater(final Channel channel) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireChannelClosed(channel);
}
});
}
/**
* Sends a {@code "channelClosed"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -418,6 +503,39 @@ public final class Channels {
ctx.getChannel(), ChannelState.OPEN, Boolean.FALSE));
}
/**
* Sends a {@code "exceptionCaught"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
* the specified {@link Channel} once the io-thread runs again.
*/
public static ChannelFuture fireExceptionCaughtLater(final Channel channel, final Throwable cause) {
return channel.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireExceptionCaught(channel, cause);
}
});
}
/**
* Sends a {@code "exceptionCaught"} event to the
* {@link ChannelUpstreamHandler} which is placed in the closest upstream
* from the handler associated with the specified
* {@link ChannelHandlerContext} once the io-thread runs again.
*/
public static ChannelFuture fireExceptionCaughtLater(final ChannelHandlerContext ctx, final Throwable cause) {
return ctx.getPipeline().execute(new Runnable() {
@Override
public void run() {
fireExceptionCaught(ctx, cause);
}
});
}
/**
* Sends a {@code "exceptionCaught"} event to the first
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
@ -444,6 +562,7 @@ public final class Channels {
new DefaultChildChannelStateEvent(channel, childChannel));
}
/**
* Sends a {@code "bind"} request to the last
* {@link ChannelDownstreamHandler} in the {@link ChannelPipeline} of

View File

@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.RejectedExecutionException;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -649,6 +650,11 @@ public class DefaultChannelPipeline implements ChannelPipeline {
return realCtx;
}
@Override
public ChannelFuture execute(Runnable task) {
return getSink().execute(this, task);
}
protected void notifyHandlerException(ChannelEvent e, Throwable t) {
if (e instanceof ExceptionEvent) {
if (logger.isWarnEnabled()) {
@ -832,5 +838,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
ChannelEvent e, ChannelPipelineException cause) throws Exception {
throw cause;
}
@Override
public ChannelFuture execute(ChannelPipeline pipeline, Runnable task) {
if (logger.isWarnEnabled()) {
logger.warn("Not attached yet; rejecting: " + task);
}
return Channels.failedFuture(pipeline.getChannel(), new RejectedExecutionException("Not attached yet"));
}
}
}

View File

@ -49,6 +49,12 @@ import java.net.SocketAddress;
* <strong>super.handleDownstream(ctx, e);</strong>
* }
* }</pre>
*
* <p>
* <strong>Caution:</strong>
* <p>
* Use the *Later(..) methods of the {@link Channels} class if you want to send an upstream event from a {@link ChannelDownstreamHandler} otherwise you may run into threading issues.
*
*/
public class SimpleChannelDownstreamHandler implements ChannelDownstreamHandler {

View File

@ -0,0 +1,58 @@
/*
* 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;
import io.netty.channel.Channel;
import io.netty.channel.DefaultChannelFuture;
public class ChannelRunnableWrapper extends DefaultChannelFuture implements Runnable {
private final Runnable task;
private boolean started;
public ChannelRunnableWrapper(Channel channel, Runnable task) {
super(channel, true);
this.task = task;
}
@Override
public void run() {
synchronized (this) {
if (!isCancelled()) {
started = true;
} else {
return;
}
}
try {
task.run();
setSuccess();
} catch (Throwable t) {
setFailure(t);
}
}
@Override
public synchronized boolean cancel() {
if (started) {
return false;
}
return super.cancel();
}
}

Some files were not shown because too many files have changed in this diff Show More