From 395d49ba71129601ff99630104958dc38757d496 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 15:23:22 +0200 Subject: [PATCH 1/8] Basic implementation of CREDENTIAL frame, parser and generator. --- .../eclipse/jetty/spdy/SessionException.java | 1 - .../jetty/spdy/frames/ControlFrameType.java | 3 +- .../jetty/spdy/frames/CredentialFrame.java | 49 ++++ .../spdy/generator/CredentialGenerator.java | 71 +++++ .../jetty/spdy/generator/Generator.java | 1 + .../jetty/spdy/parser/ControlFrameParser.java | 1 + .../spdy/parser/CredentialBodyParser.java | 262 ++++++++++++++++++ .../frames/CredentialGenerateParseTest.java | 88 ++++++ 8 files changed, 474 insertions(+), 2 deletions(-) create mode 100644 jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java create mode 100644 jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java create mode 100644 jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java create mode 100644 jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java index 3e0c1950e58..fa9a55e7c3a 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java @@ -20,7 +20,6 @@ import org.eclipse.jetty.spdy.api.SessionStatus; public class SessionException extends RuntimeException { - private final SessionStatus sessionStatus; public SessionException(SessionStatus sessionStatus) diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java index bf638d3bf56..e3b8f40ae7f 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java @@ -29,7 +29,8 @@ public enum ControlFrameType PING((short)6), GO_AWAY((short)7), HEADERS((short)8), - WINDOW_UPDATE((short)9); + WINDOW_UPDATE((short)9), + CREDENTIAL((short)10); public static ControlFrameType from(short code) { diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java new file mode 100644 index 00000000000..ac3e65b9d40 --- /dev/null +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.frames; + +import java.security.cert.Certificate; + +public class CredentialFrame extends ControlFrame +{ + private final short slot; + private final byte[] proof; + private final Certificate[] certificateChain; + + public CredentialFrame(short version, short slot, byte[] proof, Certificate[] certificateChain) + { + super(version, ControlFrameType.CREDENTIAL, (byte)0); + this.slot = slot; + this.proof = proof; + this.certificateChain = certificateChain; + } + + public short getSlot() + { + return slot; + } + + public byte[] getProof() + { + return proof; + } + + public Certificate[] getCertificateChain() + { + return certificateChain; + } +} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java new file mode 100644 index 00000000000..cb7bf319ec2 --- /dev/null +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.generator; + +import java.nio.ByteBuffer; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.spdy.ByteBufferPool; +import org.eclipse.jetty.spdy.frames.ControlFrame; +import org.eclipse.jetty.spdy.frames.CredentialFrame; + +public class CredentialGenerator extends ControlFrameGenerator +{ + public CredentialGenerator(ByteBufferPool bufferPool) + { + super(bufferPool); + } + + @Override + public ByteBuffer generate(ControlFrame frame) + { + CredentialFrame credential = (CredentialFrame)frame; + + byte[] proof = credential.getProof(); + + List certificates = serializeCertificates(credential.getCertificateChain()); + int certificatesLength = 0; + for (byte[] certificate : certificates) + certificatesLength += certificate.length; + + int frameBodyLength = 2 + 4 + proof.length + certificates.size() * 4 + certificatesLength; + + int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength; + ByteBuffer buffer = getByteBufferPool().acquire(totalLength, true); + generateControlFrameHeader(credential, frameBodyLength, buffer); + + buffer.putShort(credential.getSlot()); + buffer.putInt(proof.length); + buffer.put(proof); + for (byte[] certificate : certificates) + { + buffer.putInt(certificate.length); + buffer.put(certificate); + } + + buffer.flip(); + return buffer; + } + + private List serializeCertificates(Certificate[] certificates) + { + // TODO + return new ArrayList<>(); + } +} diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java index 70462c6ddd8..4f114b75451 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java @@ -42,6 +42,7 @@ public class Generator generators.put(ControlFrameType.GO_AWAY, new GoAwayGenerator(bufferPool)); generators.put(ControlFrameType.HEADERS, new HeadersGenerator(bufferPool, headersBlockGenerator)); generators.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateGenerator(bufferPool)); + generators.put(ControlFrameType.CREDENTIAL, new CredentialGenerator(bufferPool)); dataFrameGenerator = new DataFrameGenerator(bufferPool); } diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java index af8b78f6548..d7c9a6586c7 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java @@ -46,6 +46,7 @@ public abstract class ControlFrameParser parsers.put(ControlFrameType.GO_AWAY, new GoAwayBodyParser(this)); parsers.put(ControlFrameType.HEADERS, new HeadersBodyParser(decompressor, this)); parsers.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateBodyParser(this)); + parsers.put(ControlFrameType.CREDENTIAL, new CredentialBodyParser(this)); } public short getVersion() diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java new file mode 100644 index 00000000000..c39af7b6b0d --- /dev/null +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.parser; + +import java.nio.ByteBuffer; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jetty.spdy.SessionException; +import org.eclipse.jetty.spdy.api.SessionStatus; +import org.eclipse.jetty.spdy.frames.ControlFrameType; +import org.eclipse.jetty.spdy.frames.CredentialFrame; + +public class CredentialBodyParser extends ControlFrameBodyParser +{ + private final List certificates = new ArrayList<>(); + private final ControlFrameParser controlFrameParser; + private State state = State.SLOT; + private int totalLength; + private int cursor; + private short slot; + private int proofLength; + private byte[] proof; + private int certificateLength; + private byte[] certificate; + + public CredentialBodyParser(ControlFrameParser controlFrameParser) + { + this.controlFrameParser = controlFrameParser; + } + + @Override + public boolean parse(ByteBuffer buffer) + { + while (buffer.hasRemaining()) + { + switch (state) + { + case SLOT: + { + if (buffer.remaining() >= 2) + { + slot = buffer.getShort(); + checkSlotValid(); + state = State.PROOF_LENGTH; + } + else + { + state = State.SLOT_BYTES; + cursor = 2; + } + break; + } + case SLOT_BYTES: + { + byte currByte = buffer.get(); + --cursor; + slot += (currByte & 0xFF) << 8 * cursor; + if (cursor == 0) + { + checkSlotValid(); + state = State.PROOF_LENGTH; + } + break; + } + case PROOF_LENGTH: + { + if (buffer.remaining() >= 4) + { + proofLength = buffer.getInt() & 0x7F_FF_FF_FF; + state = State.PROOF; + } + else + { + state = State.PROOF_LENGTH_BYTES; + cursor = 4; + } + break; + } + case PROOF_LENGTH_BYTES: + { + byte currByte = buffer.get(); + --cursor; + proofLength += (currByte & 0xFF) << 8 * cursor; + if (cursor == 0) + { + proofLength &= 0x7F_FF_FF_FF; + state = State.PROOF; + } + break; + } + case PROOF: + { + totalLength = controlFrameParser.getLength() - 2 - 4 - proofLength; + proof = new byte[proofLength]; + if (buffer.remaining() >= proofLength) + { + buffer.get(proof); + state = State.CERTIFICATE_LENGTH; + if (totalLength == 0) + { + onCredential(); + return true; + } + } + else + { + state = State.PROOF_BYTES; + cursor = proofLength; + } + break; + } + case PROOF_BYTES: + { + proof[proofLength - cursor] = buffer.get(); + --cursor; + if (cursor == 0) + { + state = State.CERTIFICATE_LENGTH; + if (totalLength == 0) + { + onCredential(); + return true; + } + } + break; + } + case CERTIFICATE_LENGTH: + { + if (buffer.remaining() >= 4) + { + certificateLength = buffer.getInt() & 0x7F_FF_FF_FF; + state = State.CERTIFICATE; + } + else + { + state = State.CERTIFICATE_LENGTH_BYTES; + cursor = 4; + } + break; + } + case CERTIFICATE_LENGTH_BYTES: + { + byte currByte = buffer.get(); + --cursor; + certificateLength += (currByte & 0xFF) << 8 * cursor; + if (cursor == 0) + { + certificateLength &= 0x7F_FF_FF_FF; + state = State.CERTIFICATE; + } + break; + } + case CERTIFICATE: + { + totalLength -= 4 + certificateLength; + certificate = new byte[certificateLength]; + if (buffer.remaining() >= certificateLength) + { + buffer.get(certificate); + if (onCertificate()) + return true; + } + else + { + state = State.CERTIFICATE_BYTES; + cursor = certificateLength; + } + break; + } + case CERTIFICATE_BYTES: + { + certificate[certificateLength - cursor] = buffer.get(); + --cursor; + if (cursor == 0) + { + if (onCertificate()) + return true; + } + break; + } + default: + { + throw new IllegalStateException(); + } + } + } + return false; + } + + private void checkSlotValid() + { + if (slot <= 0) + throw new SessionException(SessionStatus.PROTOCOL_ERROR, + "Invalid slot " + slot + " for " + ControlFrameType.CREDENTIAL + " frame"); + } + + private boolean onCertificate() + { + certificates.add(deserializeCertificate(certificate)); + if (totalLength == 0) + { + onCredential(); + return true; + } + else + { + certificateLength = 0; + state = State.CERTIFICATE_LENGTH; + } + return false; + } + + private Certificate deserializeCertificate(byte[] bytes) + { + // TODO + return null; + } + + private void onCredential() + { + CredentialFrame frame = new CredentialFrame(controlFrameParser.getVersion(), slot, + Arrays.copyOf(proof, proof.length), certificates.toArray(new Certificate[certificates.size()])); + controlFrameParser.onControlFrame(frame); + reset(); + } + + private void reset() + { + state = State.SLOT; + totalLength = 0; + cursor = 0; + slot = 0; + proofLength = 0; + proof = null; + certificateLength = 0; + certificate = null; + certificates.clear(); + } + + public enum State + { + SLOT, SLOT_BYTES, PROOF_LENGTH, PROOF_LENGTH_BYTES, PROOF, PROOF_BYTES, + CERTIFICATE_LENGTH, CERTIFICATE_LENGTH_BYTES, CERTIFICATE, CERTIFICATE_BYTES + } +} diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java new file mode 100644 index 00000000000..2b210b940d6 --- /dev/null +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.frames; + +import java.nio.ByteBuffer; +import java.security.cert.Certificate; + +import org.eclipse.jetty.spdy.StandardByteBufferPool; +import org.eclipse.jetty.spdy.StandardCompressionFactory; +import org.eclipse.jetty.spdy.api.SPDY; +import org.eclipse.jetty.spdy.generator.Generator; +import org.eclipse.jetty.spdy.parser.Parser; +import org.junit.Assert; +import org.junit.Test; + +public class CredentialGenerateParseTest +{ + @Test + public void testGenerateParse() throws Exception + { + short slot = 1; + byte[] proof = new byte[]{0, 1, 2}; + Certificate[] certificates = new Certificate[0]; // TODO + CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); + Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); + ByteBuffer buffer = generator.control(frame1); + + Assert.assertNotNull(buffer); + + TestSPDYParserListener listener = new TestSPDYParserListener(); + Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); + parser.addListener(listener); + parser.parse(buffer); + ControlFrame frame2 = listener.getControlFrame(); + + Assert.assertNotNull(frame2); + Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType()); + CredentialFrame credential = (CredentialFrame)frame2; + Assert.assertEquals(SPDY.V3, credential.getVersion()); + Assert.assertEquals(0, credential.getFlags()); + Assert.assertEquals(slot, credential.getSlot()); + Assert.assertArrayEquals(proof, credential.getProof()); + Assert.assertArrayEquals(certificates, credential.getCertificateChain()); + } + + @Test + public void testGenerateParseOneByteAtATime() throws Exception + { + short slot = 1; + byte[] proof = new byte[]{0, 1, 2}; + Certificate[] certificates = new Certificate[0]; // TODO + CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); + Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); + ByteBuffer buffer = generator.control(frame1); + + Assert.assertNotNull(buffer); + + TestSPDYParserListener listener = new TestSPDYParserListener(); + Parser parser = new Parser(new StandardCompressionFactory().newDecompressor()); + parser.addListener(listener); + while (buffer.hasRemaining()) + parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()})); + ControlFrame frame2 = listener.getControlFrame(); + + Assert.assertNotNull(frame2); + Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType()); + CredentialFrame credential = (CredentialFrame)frame2; + Assert.assertEquals(SPDY.V3, credential.getVersion()); + Assert.assertEquals(0, credential.getFlags()); + Assert.assertEquals(slot, credential.getSlot()); + Assert.assertArrayEquals(proof, credential.getProof()); + Assert.assertArrayEquals(certificates, credential.getCertificateChain()); + } +} From 91105910ca9124caea28a9b1812f3f03d1d61fba Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 15:56:41 +0200 Subject: [PATCH 2/8] Added handling of Certificate encoding and decoding. --- .../spdy/generator/CredentialGenerator.java | 16 ++++++++++++++-- .../spdy/parser/CredentialBodyParser.java | 14 ++++++++++++-- .../frames/CredentialGenerateParseTest.java | 18 ++++++++++++++++-- .../spdy-core/src/test/resources/keystore.jks | Bin 0 -> 2206 bytes .../src/test/resources/truststore.jks | Bin 0 -> 916 bytes 5 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 jetty-spdy/spdy-core/src/test/resources/keystore.jks create mode 100644 jetty-spdy/spdy-core/src/test/resources/truststore.jks diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java index cb7bf319ec2..f46d39313fb 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java @@ -18,10 +18,13 @@ package org.eclipse.jetty.spdy.generator; import java.nio.ByteBuffer; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.util.ArrayList; import java.util.List; import org.eclipse.jetty.spdy.ByteBufferPool; +import org.eclipse.jetty.spdy.SessionException; +import org.eclipse.jetty.spdy.api.SessionStatus; import org.eclipse.jetty.spdy.frames.ControlFrame; import org.eclipse.jetty.spdy.frames.CredentialFrame; @@ -65,7 +68,16 @@ public class CredentialGenerator extends ControlFrameGenerator private List serializeCertificates(Certificate[] certificates) { - // TODO - return new ArrayList<>(); + try + { + List result = new ArrayList<>(certificates.length); + for (Certificate certificate : certificates) + result.add(certificate.getEncoded()); + return result; + } + catch (CertificateEncodingException x) + { + throw new SessionException(SessionStatus.PROTOCOL_ERROR, x); + } } } diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java index c39af7b6b0d..c79129ce163 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java @@ -16,8 +16,11 @@ package org.eclipse.jetty.spdy.parser; +import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -229,8 +232,15 @@ public class CredentialBodyParser extends ControlFrameBodyParser private Certificate deserializeCertificate(byte[] bytes) { - // TODO - return null; + try + { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + return certificateFactory.generateCertificate(new ByteArrayInputStream(bytes)); + } + catch (CertificateException x) + { + throw new SessionException(SessionStatus.PROTOCOL_ERROR, x); + } } private void onCredential() diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java index 2b210b940d6..0678c768ebc 100644 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java @@ -16,7 +16,9 @@ package org.eclipse.jetty.spdy.frames; +import java.io.InputStream; import java.nio.ByteBuffer; +import java.security.KeyStore; import java.security.cert.Certificate; import org.eclipse.jetty.spdy.StandardByteBufferPool; @@ -24,6 +26,7 @@ import org.eclipse.jetty.spdy.StandardCompressionFactory; import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.parser.Parser; +import org.eclipse.jetty.util.resource.Resource; import org.junit.Assert; import org.junit.Test; @@ -34,7 +37,10 @@ public class CredentialGenerateParseTest { short slot = 1; byte[] proof = new byte[]{0, 1, 2}; - Certificate[] certificates = new Certificate[0]; // TODO + Certificate[] temp = loadCertificates(); + Certificate[] certificates = new Certificate[temp.length * 2]; + System.arraycopy(temp, 0, certificates, 0, temp.length); + System.arraycopy(temp, 0, certificates, temp.length, temp.length); CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); ByteBuffer buffer = generator.control(frame1); @@ -62,7 +68,7 @@ public class CredentialGenerateParseTest { short slot = 1; byte[] proof = new byte[]{0, 1, 2}; - Certificate[] certificates = new Certificate[0]; // TODO + Certificate[] certificates = loadCertificates(); CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); ByteBuffer buffer = generator.control(frame1); @@ -85,4 +91,12 @@ public class CredentialGenerateParseTest Assert.assertArrayEquals(proof, credential.getProof()); Assert.assertArrayEquals(certificates, credential.getCertificateChain()); } + + private Certificate[] loadCertificates() throws Exception + { + KeyStore keyStore = KeyStore.getInstance("JKS"); + InputStream keyStoreStream = Resource.newResource("src/test/resources/keystore.jks").getInputStream(); + keyStore.load(keyStoreStream, "storepwd".toCharArray()); + return keyStore.getCertificateChain("mykey"); + } } diff --git a/jetty-spdy/spdy-core/src/test/resources/keystore.jks b/jetty-spdy/spdy-core/src/test/resources/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..428ba54776ede2fdcdeedd879edb927c2abd9953 GIT binary patch literal 2206 zcmcgt`9Bkm8{cNkoMUp6gmShKn!AQX*(l6Nj(i=TnQPOKYtv{*Wg>ItE=Q!pRYH8a z$Sp#S#2lYw#aw;$y9u4T}83H*%lp zAKZay0sy=q1Qoo85aAQh;$ zD(c2EIN#D7WwYDLKUg!CotQPD@dp;5FR#bgaace(^x$6g5frD~(_b(MI^J&*A2DRp zf5Q2onfE(zvUb9|9C`66)YFRNM6~xrz4;iVbU=P|*YT2eWHFJJtr+M@zt2qPm)K~rRcqcs=LM12)PX0TT%QO zlf*xkqD3}7l)1J`5W(>=9nR0e6j-<79<11v3ZuXXcQpoCsqY~n`$FN+S}hcVm5Y>G zXnD{@DYs1@{S0z(lW+?86LWKtku$$-(khsh>0qRUXn=84`GRn?77M^_JY`durnN;KE zW#OJ`h<6xcB{I))ekGpc*Ylt}0cx4|OMBDPQvx4`r`}4Ze5_ipdObGMTi3bZHd5PC zcY0;?uBWu$PSvjJeb87nY7ghNv?%M@SoDl6IWt`bQCosfSh$#D6$ea~QhKM^ud2Ut z+9PYJuVpoELmN-A`F$BicO{BSYg@#tS%avVfb}DxL)|NanJ)#zB!2~?#Ot%H7--9N zU$bs0fS5G!m5M4&WK3#a|H|Tgw*?X-;H+Lu@kwA>qSR~7UC7b)7MJXTn6PG>n@8jP zW+}F^X$$c;U~4ryqRF; z>`j!tbLMK4ZGyY643|~?%Mu#fm!l%wAKjBDmd+VYmp3S#$scD$~bxbf|z#)hShN0*AhRaPDcmqrftGlHq4^54MM$Xfy(2> zH8QYVMzmn_oHbvJCB`IN~E&{1*h&0gEM{e zKvWvzp(!BqMX8`t#)~0nq}Wa zr6>FRPyp;AAB&)1$5@;r$23J{K&~>TWjZf7V$wFzmGM95CXhFG1cJNVAXks}C+&2- zbf9Qn*D8N}Afd2kpwDxns3%1uaFhAqDV8ksWiWY|quuLGZ0)SqrJ!Y8yX}@}IyC$C zQ3rCUsn}#>F#D8%D?q~ySy4j&he%Bs{{7V%rl!ui`@KQP?NTi+_iN{cwom&9RaMRR zB~z!hz|0HAgB9_Ijvpe-zr#jLbckJsc>vmo{+im?t8lA;N#fD4?{lb&J0V8Gocq%; f1ihv=QIDh{M_<9V+45Z2{KE4_qW}V3B0uV%GgrOJ literal 0 HcmV?d00001 diff --git a/jetty-spdy/spdy-core/src/test/resources/truststore.jks b/jetty-spdy/spdy-core/src/test/resources/truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..839cb8c35151c2b7c64afca24b6b72caad070a05 GIT binary patch literal 916 zcmezO_TO6u1_mY|W(3o$xs} zE~X|%Muz1J{3AIFGbaABoD&*5saD@gH|APIn|qhRGl}gsUzm=o9G*UXZaLfkb^*)o zjA*-gTf)`m_MQJYE&gJ}p^PHkrj!4^W|XX5a=N7A{;n#yaON&k_bHloe-^*hm?Z91 zlB>xeD=<(C>yn{9D54u}krkl}HQ(Uscha(++qf!T9y+xaEfnXd1O zi0)T?voO%;QH9LK;*_O3mBblqm)!31vU@hm;^%>mh5U@y3R%l0gzi`2yxH!+?kPOi zt!Tnsz1x9B3U2~8STZp)GB6^C5HPs_Lx_=~O<3xi>MmQ;D_g$D<_pdct`+TyzWTQ= zW5Finm(sGEe;ty^>vg$!cV)t>;H#Mev23$*WWBpyJ}Ir;RW+Htrt6{Pk&qz&-XG2@ z8@{&Lu%DX7m47Uny+-3w`=4V611q#Ub(U`xZCtSK^2LO^3(s|HW&N14dV4@A&(kX% z*S_eUPs-bSWRp>avt;CP@7K+G&3=b&1eO-s3f`;Cf91p#$)FW&xME3L8sEBQQDVCvfG>mdwqnk+GXd2ihXqpv z;usF(WoYYmu8DZZa4%1z=+hI+*gpkUykAy5tj#grb*gH!M6TqIcifYBGVe^&T#-2O K*=+x>r_BKeJV|!| literal 0 HcmV?d00001 From fb34f9b8247c1a4b986bdf8ac439f184b4d36459 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 17:08:08 +0200 Subject: [PATCH 3/8] Added handling of Credential frames (for now just issuing a warning). --- .../java/org/eclipse/jetty/spdy/StandardSession.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java index 2b47c3aa4a9..6fd61b6653e 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java @@ -52,6 +52,7 @@ import org.eclipse.jetty.spdy.api.StreamStatus; import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.frames.ControlFrame; import org.eclipse.jetty.spdy.frames.ControlFrameType; +import org.eclipse.jetty.spdy.frames.CredentialFrame; import org.eclipse.jetty.spdy.frames.DataFrame; import org.eclipse.jetty.spdy.frames.GoAwayFrame; import org.eclipse.jetty.spdy.frames.HeadersFrame; @@ -328,6 +329,11 @@ public class StandardSession implements ISession, Parser.Listener, Handler Date: Fri, 1 Jun 2012 17:31:02 +0200 Subject: [PATCH 4/8] Added handling of the "slot" field in SYN_STREAM frames. Modified parser and generator, and the session implementation for now ignores this field. --- .../org/eclipse/jetty/spdy/StandardSession.java | 3 ++- .../eclipse/jetty/spdy/frames/SynStreamFrame.java | 9 ++++++++- .../jetty/spdy/generator/SynStreamGenerator.java | 2 +- .../jetty/spdy/parser/SynStreamBodyParser.java | 7 +++++-- .../org/eclipse/jetty/spdy/StandardSessionTest.java | 13 ++++++------- .../org/eclipse/jetty/spdy/StandardStreamTest.java | 12 ++++++------ .../spdy/frames/SynStreamGenerateParseTest.java | 8 ++++++-- .../jetty/spdy/parser/UnknownControlFrameTest.java | 2 +- 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java index 6fd61b6653e..e2b7a96ee42 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java @@ -158,7 +158,8 @@ public class StandardSession implements ISession, Parser.Listener, Handler (SynInfo.FLAG_CLOSE | PushSynInfo.FLAG_UNIDIRECTIONAL)) throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_STREAM); - SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, priority, new Headers(headers, true)); + SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, priority, slot, new Headers(headers, true)); controlFrameParser.onControlFrame(frame); reset(); diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java index 48d1e669822..07822e26676 100644 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java @@ -404,8 +404,8 @@ public class StandardSessionTest setControllerWriteExpectationToFail(true); final CountDownLatch failedCalledLatch = new CountDownLatch(2); - SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2,SynInfo.FLAG_CLOSE,1,0,(byte)0,null); - IStream stream = new StandardStream(synStreamFrame,session,null); + SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null); + IStream stream = new StandardStream(synStreamFrame, session, null); stream.updateWindowSize(8192); Handler.Adapter handler = new Handler.Adapter() { @@ -417,13 +417,12 @@ public class StandardSessionTest }; // first data frame should fail on controller.write() - stream.data(new StringDataInfo("data",false),5,TimeUnit.SECONDS,handler); + stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, handler); // second data frame should fail without controller.writer() as the connection is expected to be broken after first controller.write() call failed. - stream.data(new StringDataInfo("data",false),5,TimeUnit.SECONDS,handler); - - verify(controller,times(1)).write(any(ByteBuffer.class),any(Handler.class),any(FrameBytes.class)); - assertThat("Handler.failed has been called twice",failedCalledLatch.await(5,TimeUnit.SECONDS),is(true)); + stream.data(new StringDataInfo("data", false), 5, TimeUnit.SECONDS, handler); + verify(controller, times(1)).write(any(ByteBuffer.class), any(Handler.class), any(FrameBytes.class)); + assertThat("Handler.failed has been called twice", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true)); } private IStream createStream() throws InterruptedException, ExecutionException, TimeoutException diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java index 01846648d93..314905bf4a3 100644 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java @@ -120,12 +120,12 @@ public class StandardStreamTest @Test(expected = IllegalStateException.class) public void testSendDataOnHalfClosedStream() throws InterruptedException, ExecutionException, TimeoutException { - SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2,SynInfo.FLAG_CLOSE,1,0,(byte)0,null); - IStream stream = new StandardStream(synStreamFrame,session,null); + SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null); + IStream stream = new StandardStream(synStreamFrame, session, null); stream.updateWindowSize(8192); - stream.updateCloseState(synStreamFrame.isClose(),true); - assertThat("stream is half closed",stream.isHalfClosed(),is(true)); - stream.data(new StringDataInfo("data on half closed stream",true)); - verify(session,never()).data(any(IStream.class),any(DataInfo.class),anyInt(),any(TimeUnit.class),any(Handler.class),any(void.class)); + stream.updateCloseState(synStreamFrame.isClose(), true); + assertThat("stream is half closed", stream.isHalfClosed(), is(true)); + stream.data(new StringDataInfo("data on half closed stream", true)); + verify(session, never()).data(any(IStream.class), any(DataInfo.class), anyInt(), any(TimeUnit.class), any(Handler.class), any(void.class)); } } diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java index 2fac2bbe9f3..a1268a2db31 100644 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java @@ -37,10 +37,11 @@ public class SynStreamGenerateParseTest int streamId = 13; int associatedStreamId = 11; byte priority = 3; + short slot = 5; Headers headers = new Headers(); headers.put("a", "b"); headers.put("c", "d"); - SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, headers); + SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); ByteBuffer buffer = generator.control(frame1); @@ -60,6 +61,7 @@ public class SynStreamGenerateParseTest Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId()); Assert.assertEquals(flags, synStream.getFlags()); Assert.assertEquals(priority, synStream.getPriority()); + Assert.assertEquals(slot, synStream.getSlot()); Assert.assertEquals(headers, synStream.getHeaders()); } @@ -70,10 +72,11 @@ public class SynStreamGenerateParseTest int streamId = 13; int associatedStreamId = 11; byte priority = 3; + short slot = 5; Headers headers = new Headers(); headers.put("a", "b"); headers.put("c", "d"); - SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, headers); + SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory().newCompressor()); ByteBuffer buffer = generator.control(frame1); @@ -94,6 +97,7 @@ public class SynStreamGenerateParseTest Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId()); Assert.assertEquals(flags, synStream.getFlags()); Assert.assertEquals(priority, synStream.getPriority()); + Assert.assertEquals(slot, synStream.getSlot()); Assert.assertEquals(headers, synStream.getHeaders()); } } diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java index 750f407d4b4..ffecdc10b83 100644 --- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java +++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java @@ -23,7 +23,7 @@ public class UnknownControlFrameTest @Test public void testUnknownControlFrame() throws Exception { - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, new Headers()); + SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Headers()); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); ByteBuffer buffer = generator.control(frame); // Change the frame type to unknown From d12c2fec2163cb6750af005751f85540fdb2e2bf Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 17:46:39 +0200 Subject: [PATCH 5/8] Renamed enum constant. --- .../eclipse/jetty/spdy/parser/GoAwayBodyParser.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java index 753ad804d4d..926948c4f4a 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.spdy.frames.GoAwayFrame; public class GoAwayBodyParser extends ControlFrameBodyParser { private final ControlFrameParser controlFrameParser; - private State state = State.LAST_STREAM_ID; + private State state = State.LAST_GOOD_STREAM_ID; private int cursor; private int lastStreamId; private int statusCode; @@ -41,7 +41,7 @@ public class GoAwayBodyParser extends ControlFrameBodyParser { switch (state) { - case LAST_STREAM_ID: + case LAST_GOOD_STREAM_ID: { if (buffer.remaining() >= 4) { @@ -66,12 +66,12 @@ public class GoAwayBodyParser extends ControlFrameBodyParser } else { - state = State.LAST_STREAM_ID_BYTES; + state = State.LAST_GOOD_STREAM_ID_BYTES; cursor = 4; } break; } - case LAST_STREAM_ID_BYTES: + case LAST_GOOD_STREAM_ID_BYTES: { byte currByte = buffer.get(); --cursor; @@ -144,7 +144,7 @@ public class GoAwayBodyParser extends ControlFrameBodyParser private void reset() { - state = State.LAST_STREAM_ID; + state = State.LAST_GOOD_STREAM_ID; cursor = 0; lastStreamId = 0; statusCode = 0; @@ -152,6 +152,6 @@ public class GoAwayBodyParser extends ControlFrameBodyParser private enum State { - LAST_STREAM_ID, LAST_STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES + LAST_GOOD_STREAM_ID, LAST_GOOD_STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES } } From 70e4a103ec539d97a009d599469c982be877b90d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 17:52:47 +0200 Subject: [PATCH 6/8] Implemented correctly SPDY v2 parsing and generation of the HEADERS frame. --- .../spdy/generator/HeadersGenerator.java | 5 ++ .../jetty/spdy/parser/HeadersBodyParser.java | 48 +++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java index e979330ff77..9a894f6c0af 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java @@ -20,6 +20,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.spdy.ByteBufferPool; import org.eclipse.jetty.spdy.SessionException; +import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.SessionStatus; import org.eclipse.jetty.spdy.frames.ControlFrame; import org.eclipse.jetty.spdy.frames.HeadersFrame; @@ -43,6 +44,8 @@ public class HeadersGenerator extends ControlFrameGenerator ByteBuffer headersBuffer = headersBlockGenerator.generate(version, headers.getHeaders()); int frameBodyLength = 4; + if (frame.getVersion() == SPDY.V2) + frameBodyLength += 2; int frameLength = frameBodyLength + headersBuffer.remaining(); if (frameLength > 0xFF_FF_FF) @@ -58,6 +61,8 @@ public class HeadersGenerator extends ControlFrameGenerator generateControlFrameHeader(headers, frameLength, buffer); buffer.putInt(headers.getStreamId() & 0x7F_FF_FF_FF); + if (frame.getVersion() == SPDY.V2) + buffer.putShort((short)0); buffer.put(headersBuffer); diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java index 98bbc7ca258..208d66734aa 100644 --- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java +++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.spdy.CompressionFactory; import org.eclipse.jetty.spdy.api.Headers; import org.eclipse.jetty.spdy.api.HeadersInfo; +import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.frames.ControlFrameType; import org.eclipse.jetty.spdy.frames.HeadersFrame; @@ -51,7 +52,7 @@ public class HeadersBodyParser extends ControlFrameBodyParser if (buffer.remaining() >= 4) { streamId = buffer.getInt() & 0x7F_FF_FF_FF; - state = State.HEADERS; + state = State.ADDITIONAL; } else { @@ -68,14 +69,55 @@ public class HeadersBodyParser extends ControlFrameBodyParser if (cursor == 0) { streamId &= 0x7F_FF_FF_FF; - state = State.HEADERS; + state = State.ADDITIONAL; } break; } + case ADDITIONAL: + { + switch (controlFrameParser.getVersion()) + { + case SPDY.V2: + { + if (buffer.remaining() >= 2) + { + buffer.getShort(); + state = State.HEADERS; + } + else + { + state = State.ADDITIONAL_BYTES; + cursor = 2; + } + break; + } + case SPDY.V3: + { + state = State.HEADERS; + break; + } + default: + { + throw new IllegalStateException(); + } + } + break; + } + case ADDITIONAL_BYTES: + { + assert controlFrameParser.getVersion() == SPDY.V2; + buffer.get(); + --cursor; + if (cursor == 0) + state = State.HEADERS; + break; + } case HEADERS: { short version = controlFrameParser.getVersion(); int length = controlFrameParser.getLength() - 4; + if (version == SPDY.V2) + length -= 2; if (headersBlockParser.parse(streamId, version, length, buffer)) { byte flags = controlFrameParser.getFlags(); @@ -109,7 +151,7 @@ public class HeadersBodyParser extends ControlFrameBodyParser private enum State { - STREAM_ID, STREAM_ID_BYTES, HEADERS + STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS } private class HeadersHeadersBlockParser extends HeadersBlockParser From f872676a65dd0be0042af848c9dc8da585f840d6 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 19:05:25 +0200 Subject: [PATCH 7/8] Added handling of the "slot" field in SYN_STREAM frames. Modified parser and generator, and the session implementation for now ignores this field. --- .../test/java/org/eclipse/jetty/spdy/ClosedStreamTest.java | 4 ++-- .../src/test/java/org/eclipse/jetty/spdy/PushStreamTest.java | 2 +- .../java/org/eclipse/jetty/spdy/UnsupportedVersionTest.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/ClosedStreamTest.java b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/ClosedStreamTest.java index e58209c8b27..0d51b27c910 100644 --- a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/ClosedStreamTest.java +++ b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/ClosedStreamTest.java @@ -213,7 +213,7 @@ public class ClosedStreamTest extends AbstractTest final Generator generator = new Generator(new StandardByteBufferPool(),new StandardCompressionFactory().newCompressor()); int streamId = 1; - ByteBuffer synData = generator.control(new SynStreamFrame(version,SynInfo.FLAG_CLOSE, streamId,0,(byte)0,new Headers())); + ByteBuffer synData = generator.control(new SynStreamFrame(version,SynInfo.FLAG_CLOSE, streamId,0,(byte)0,(short)0,new Headers())); final SocketChannel socketChannel = SocketChannel.open(startServer); socketChannel.write(synData); @@ -261,7 +261,7 @@ public class ClosedStreamTest extends AbstractTest Assert.assertThat(buffer.hasRemaining(), is(false)); assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5,TimeUnit.SECONDS), is(true)); - + socketChannel.close(); } } diff --git a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/PushStreamTest.java b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/PushStreamTest.java index c3118f7eb54..d9073fd2270 100644 --- a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/PushStreamTest.java +++ b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/PushStreamTest.java @@ -414,7 +414,7 @@ public class PushStreamTest extends AbstractTest final SocketChannel channel = SocketChannel.open(serverAddress); final Generator generator = new Generator(new StandardByteBufferPool(),new StandardCompressionFactory.StandardCompressor()); int streamId = 1; - ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version,(byte)0,streamId,0,(byte)0,new Headers())); + ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version,(byte)0,streamId,0,(byte)0,(short)0,new Headers())); channel.write(writeBuffer); assertThat("writeBuffer is fully written",writeBuffer.hasRemaining(), is(false)); diff --git a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/UnsupportedVersionTest.java b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/UnsupportedVersionTest.java index 78f2163272d..0dbef02f2a3 100644 --- a/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/UnsupportedVersionTest.java +++ b/jetty-spdy/spdy-jetty/src/test/java/org/eclipse/jetty/spdy/UnsupportedVersionTest.java @@ -44,7 +44,7 @@ public class UnsupportedVersionTest extends AbstractTest } }); - SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, new Headers()); + SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Headers()); Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor()); ByteBuffer buffer = generator.control(frame); // Replace the version byte with an unsupported version From 6ff1a5fddce7d1c3aa6f3dbbac733fdea995e2f3 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Fri, 1 Jun 2012 19:29:07 +0200 Subject: [PATCH 8/8] Implemented SPDY/3 HTTP layering. --- .../jetty/spdy/http/HTTPSPDYHeader.java | 75 +++++ .../http/ServerHTTPSPDYAsyncConnection.java | 71 ++-- .../ServerHTTPSPDYAsyncConnectionFactory.java | 4 +- .../jetty/spdy/http/AbstractHTTPSPDYTest.java | 18 +- .../spdy/http/ReferrerPushStrategyTest.java | 7 +- ...PDYTest.java => ServerHTTPSPDYv2Test.java} | 302 +++++++++--------- .../jetty/spdy/http/ServerHTTPSPDYv3Test.java | 28 ++ .../ServerSPDYAsyncConnectionFactory.java | 5 + 8 files changed, 319 insertions(+), 191 deletions(-) create mode 100644 jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java rename jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/{ServerHTTPSPDYTest.java => ServerHTTPSPDYv2Test.java} (77%) create mode 100644 jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv3Test.java diff --git a/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java new file mode 100644 index 00000000000..76fed62346f --- /dev/null +++ b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.http; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.spdy.api.SPDY; + +public enum HTTPSPDYHeader +{ + METHOD("method", ":method"), + URI("url", ":path"), + VERSION("version", ":version"), + SCHEME("scheme", ":scheme"), + HOST("host", ":host"), + STATUS("status", ":status"); + + public static HTTPSPDYHeader from(short version, String name) + { + switch (version) + { + case SPDY.V2: + return Names.v2Names.get(name); + case SPDY.V3: + return Names.v3Names.get(name); + default: + throw new IllegalStateException(); + } + } + + private final String v2Name; + private final String v3Name; + + private HTTPSPDYHeader(String v2Name, String v3Name) + { + this.v2Name = v2Name; + Names.v2Names.put(v2Name, this); + this.v3Name = v3Name; + Names.v3Names.put(v3Name, this); + } + + public String name(short version) + { + switch (version) + { + case SPDY.V2: + return v2Name; + case SPDY.V3: + return v3Name; + default: + throw new IllegalStateException(); + } + } + + private static class Names + { + private static final Map v2Names = new HashMap<>(); + private static final Map v3Names = new HashMap<>(); + } +} diff --git a/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnection.java b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnection.java index f82b3f08e1a..9dbe174b9a9 100644 --- a/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnection.java +++ b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnection.java @@ -66,6 +66,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem private final Queue tasks = new LinkedList<>(); private final BlockingQueue dataInfos = new LinkedBlockingQueue<>(); + private final short version; private final SPDYAsyncConnection connection; private final PushStrategy pushStrategy; private final Stream stream; @@ -75,9 +76,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem private volatile State state = State.INITIAL; private boolean dispatched; // Guarded by synchronization on tasks - public ServerHTTPSPDYAsyncConnection(Connector connector, AsyncEndPoint endPoint, Server server, SPDYAsyncConnection connection, PushStrategy pushStrategy, Stream stream) + public ServerHTTPSPDYAsyncConnection(Connector connector, AsyncEndPoint endPoint, Server server, short version, SPDYAsyncConnection connection, PushStrategy pushStrategy, Stream stream) { super(connector, endPoint, server); + this.version = version; this.connection = connection; this.pushStrategy = pushStrategy; this.stream = stream; @@ -159,9 +161,9 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem } case REQUEST: { - Headers.Header method = headers.get("method"); - Headers.Header uri = headers.get("url"); - Headers.Header version = headers.get("version"); + Headers.Header method = headers.get(HTTPSPDYHeader.METHOD.name(version)); + Headers.Header uri = headers.get(HTTPSPDYHeader.URI.name(version)); + Headers.Header version = headers.get(HTTPSPDYHeader.VERSION.name(this.version)); if (method == null || uri == null || version == null) throw new HttpException(HttpStatus.BAD_REQUEST_400); @@ -181,15 +183,19 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem for (Headers.Header header : headers) { String name = header.name(); + + // Skip special SPDY headers, unless it's the "host" header + HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(version, name); + if (specialHeader != null) + { + if (specialHeader == HTTPSPDYHeader.HOST) + name = "host"; + else + continue; + } + switch (name) { - case "method": - case "version": - case "url": - { - // Skip request line headers - continue; - } case "connection": case "keep-alive": case "proxy-connection": @@ -264,8 +270,8 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem else { Headers headers = new Headers(); - headers.put("status", String.valueOf(status)); - headers.put("version", "HTTP/1.1"); + headers.put(HTTPSPDYHeader.STATUS.name(version), String.valueOf(status)); + headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); stream.reply(new ReplyInfo(headers, true)); } } @@ -393,21 +399,22 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem { if (!stream.isUnidirectional()) stream.reply(replyInfo); - if (replyInfo.getHeaders().get("status").value().startsWith("200") && !stream.isClosed() && !isIfModifiedSinceHeaderPresent()) + if (replyInfo.getHeaders().get(HTTPSPDYHeader.STATUS.name(version)).value().startsWith("200") && + !stream.isClosed() && !isIfModifiedSinceHeaderPresent()) { // We have a 200 OK with some content to send - Headers.Header scheme = headers.get("scheme"); - Headers.Header host = headers.get("host"); - Headers.Header url = headers.get("url"); - Set pushResources = pushStrategy.apply(stream, this.headers, replyInfo.getHeaders()); - String referrer = new StringBuilder(scheme.value()).append("://").append(host.value()).append(url.value()).toString(); + Headers.Header scheme = headers.get(HTTPSPDYHeader.SCHEME.name(version)); + Headers.Header host = headers.get(HTTPSPDYHeader.HOST.name(version)); + Headers.Header uri = headers.get(HTTPSPDYHeader.URI.name(version)); + Set pushResources = pushStrategy.apply(stream, headers, replyInfo.getHeaders()); + String referrer = new StringBuilder(scheme.value()).append("://").append(host.value()).append(uri.value()).toString(); for (String pushURL : pushResources) { final Headers pushHeaders = new Headers(); - pushHeaders.put("method", "GET"); - pushHeaders.put("url", pushURL); - pushHeaders.put("version", "HTTP/1.1"); + pushHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET"); + pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushURL); + pushHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); pushHeaders.put(scheme); pushHeaders.put(host); pushHeaders.put("referer", referrer); @@ -418,7 +425,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem @Override public void completed(Stream pushStream) { - Synchronous pushConnection = new Synchronous(getConnector(), getEndPoint(), getServer(), connection, pushStrategy, pushStream); + Synchronous pushConnection = new Synchronous(getConnector(), getEndPoint(), getServer(), version, connection, pushStrategy, pushStream); pushConnection.beginRequest(pushHeaders, true); } }); @@ -427,12 +434,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem } private boolean isIfModifiedSinceHeaderPresent() - { - if (headers.get("if-modified-since") != null) - return true; - return false; - } - + { + return headers.get("if-modified-since") != null; + } + private Buffer consumeContent(long maxIdleTime) throws IOException, InterruptedException { while (true) @@ -614,11 +619,11 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem { Headers headers = new Headers(); String version = "HTTP/1.1"; - headers.put("version", version); + headers.put(HTTPSPDYHeader.VERSION.name(ServerHTTPSPDYAsyncConnection.this.version), version); StringBuilder status = new StringBuilder().append(_status); if (_reason != null) status.append(" ").append(_reason.toString("UTF-8")); - headers.put("status", status.toString()); + headers.put(HTTPSPDYHeader.STATUS.name(ServerHTTPSPDYAsyncConnection.this.version), status.toString()); logger.debug("HTTP < {} {}", version, status); if (fields != null) @@ -747,9 +752,9 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem private static class Synchronous extends ServerHTTPSPDYAsyncConnection { - private Synchronous(Connector connector, AsyncEndPoint endPoint, Server server, SPDYAsyncConnection connection, PushStrategy pushStrategy, Stream stream) + private Synchronous(Connector connector, AsyncEndPoint endPoint, Server server, short version, SPDYAsyncConnection connection, PushStrategy pushStrategy, Stream stream) { - super(connector, endPoint, server, connection, pushStrategy, stream); + super(connector, endPoint, server, version, connection, pushStrategy, stream); } @Override diff --git a/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnectionFactory.java b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnectionFactory.java index 0370ea87779..b3d4a5237c0 100644 --- a/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnectionFactory.java +++ b/jetty-spdy/spdy-jetty-http/src/main/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYAsyncConnectionFactory.java @@ -78,8 +78,8 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect logger.debug("Received {} on {}", synInfo, stream); HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(endPoint, stream); - ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector, - asyncEndPoint, connector.getServer(), (SPDYAsyncConnection)endPoint.getConnection(), + ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector, asyncEndPoint, + connector.getServer(), getVersion(), (SPDYAsyncConnection)endPoint.getConnection(), pushStrategy, stream); asyncEndPoint.setConnection(connection); stream.setAttribute(CONNECTION_ATTRIBUTE, connection); diff --git a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/AbstractHTTPSPDYTest.java b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/AbstractHTTPSPDYTest.java index c5fc2017a54..b875379f3ba 100644 --- a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/AbstractHTTPSPDYTest.java +++ b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/AbstractHTTPSPDYTest.java @@ -54,9 +54,14 @@ public abstract class AbstractHTTPSPDYTest protected SPDYServerConnector connector; protected InetSocketAddress startHTTPServer(Handler handler) throws Exception + { + return startHTTPServer(SPDY.V2, handler); + } + + protected InetSocketAddress startHTTPServer(short version, Handler handler) throws Exception { server = new Server(); - connector = newHTTPSPDYServerConnector(); + connector = newHTTPSPDYServerConnector(version); connector.setPort(0); server.addConnector(connector); server.setHandler(handler); @@ -64,16 +69,21 @@ public abstract class AbstractHTTPSPDYTest return new InetSocketAddress("localhost", connector.getLocalPort()); } - protected SPDYServerConnector newHTTPSPDYServerConnector() + protected SPDYServerConnector newHTTPSPDYServerConnector(short version) { // For these tests, we need the connector to speak HTTP over SPDY even in non-SSL SPDYServerConnector connector = new HTTPSPDYServerConnector(); - AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(SPDY.V2, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new PushStrategy.None()); + AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new PushStrategy.None()); connector.setDefaultAsyncConnectionFactory(defaultFactory); return connector; } protected Session startClient(InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception + { + return startClient(SPDY.V2, socketAddress, listener); + } + + protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception { if (clientFactory == null) { @@ -82,7 +92,7 @@ public abstract class AbstractHTTPSPDYTest clientFactory = newSPDYClientFactory(threadPool); clientFactory.start(); } - return clientFactory.newSPDYClient(SPDY.V2).connect(socketAddress, listener).get(5, TimeUnit.SECONDS); + return clientFactory.newSPDYClient(version).connect(socketAddress, listener).get(5, TimeUnit.SECONDS); } protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) diff --git a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ReferrerPushStrategyTest.java index 8f7967f020a..4215118d5a1 100644 --- a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ReferrerPushStrategyTest.java +++ b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ReferrerPushStrategyTest.java @@ -16,7 +16,6 @@ import org.eclipse.jetty.spdy.SPDYServerConnector; import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.Headers; import org.eclipse.jetty.spdy.api.ReplyInfo; -import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.Stream; @@ -28,10 +27,10 @@ import org.junit.Test; public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest { @Override - protected SPDYServerConnector newHTTPSPDYServerConnector() + protected SPDYServerConnector newHTTPSPDYServerConnector(short version) { - SPDYServerConnector connector = super.newHTTPSPDYServerConnector(); - AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(SPDY.V2, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new ReferrerPushStrategy()); + SPDYServerConnector connector = super.newHTTPSPDYServerConnector(version); + AsyncConnectionFactory defaultFactory = new ServerHTTPSPDYAsyncConnectionFactory(version, connector.getByteBufferPool(), connector.getExecutor(), connector.getScheduler(), connector, new ReferrerPushStrategy()); connector.setDefaultAsyncConnectionFactory(defaultFactory); return connector; } diff --git a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYTest.java b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv2Test.java similarity index 77% rename from jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYTest.java rename to jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv2Test.java index 8b0c85e54a7..15fb5c2e2d8 100644 --- a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYTest.java +++ b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv2Test.java @@ -40,6 +40,7 @@ import org.eclipse.jetty.spdy.api.BytesDataInfo; import org.eclipse.jetty.spdy.api.DataInfo; import org.eclipse.jetty.spdy.api.Headers; import org.eclipse.jetty.spdy.api.ReplyInfo; +import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Stream; import org.eclipse.jetty.spdy.api.StreamFrameListener; @@ -48,14 +49,19 @@ import org.eclipse.jetty.spdy.api.SynInfo; import org.junit.Assert; import org.junit.Test; -public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest +public class ServerHTTPSPDYv2Test extends AbstractHTTPSPDYTest { + protected short version() + { + return SPDY.V2; + } + @Test public void testSimpleGET() throws Exception { final String path = "/foo"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -71,11 +77,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", path); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), path); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() { @@ -84,7 +90,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }); @@ -99,7 +105,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String query = "p=1"; final String uri = path + "?" + query; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -115,11 +121,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", uri); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), uri); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() { @@ -128,7 +134,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }); @@ -141,7 +147,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final String path = "/foo"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -156,11 +162,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "HEAD"); - headers.put("url", path); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "HEAD"); + headers.put(HTTPSPDYHeader.URI.name(version()), path); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() { @@ -169,7 +175,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }); @@ -183,7 +189,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String path = "/foo"; final String data = "a=1&b=2"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -206,11 +212,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", path); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), path); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); headers.put("content-type", "application/x-www-form-urlencoded"); final CountDownLatch replyLatch = new CountDownLatch(1); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() @@ -220,7 +226,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }).get(5, TimeUnit.SECONDS); @@ -237,7 +243,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String data1 = "a=1&"; final String data2 = "b=2"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -252,11 +258,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", path); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), path); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); headers.put("content-type", "application/x-www-form-urlencoded"); final CountDownLatch replyLatch = new CountDownLatch(1); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() @@ -266,7 +272,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }).get(5, TimeUnit.SECONDS); @@ -286,7 +292,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String data1 = "a=1&"; final String data2 = "b=2"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -301,11 +307,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", path); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), path); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); headers.put("content-type", "application/x-www-form-urlencoded"); final CountDownLatch replyLatch = new CountDownLatch(1); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() @@ -315,7 +321,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.toString(), replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }).get(5, TimeUnit.SECONDS); @@ -332,7 +338,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final String data = "0123456789ABCDEF"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -347,11 +353,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -361,7 +367,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -383,7 +389,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final char data = 'x'; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -398,11 +404,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -412,7 +418,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -437,7 +443,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String data1 = "0123456789ABCDEF"; final String data2 = "FEDCBA9876543210"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -454,11 +460,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(2); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -472,7 +478,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replyFrames.incrementAndGet()); Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -499,7 +505,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final byte[] data = new byte[128 * 1024]; Arrays.fill(data, (byte)'x'); final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -514,11 +520,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -530,7 +536,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -556,7 +562,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final byte[] data = new byte[128 * 1024]; Arrays.fill(data, (byte)'y'); final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -572,11 +578,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -588,7 +594,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -613,7 +619,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final String data = "0123456789ABCDEF"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -630,11 +636,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -646,7 +652,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -674,7 +680,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String data1 = "0123456789ABCDEF"; final String data2 = "FEDCBA9876543210"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -693,11 +699,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -709,7 +715,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -736,7 +742,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final String suffix = "/redirect"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -751,11 +757,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() { @@ -767,7 +773,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replies.incrementAndGet()); Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("302")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("302")); Assert.assertTrue(replyHeaders.get("location").value().endsWith(suffix)); replyLatch.countDown(); } @@ -780,7 +786,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest public void testGETWithSendError() throws Exception { final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -793,11 +799,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -810,7 +816,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replies.incrementAndGet()); Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("404")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("404")); replyLatch.countDown(); } @@ -829,7 +835,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest @Test public void testGETWithException() throws Exception { - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -840,11 +846,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() { @@ -856,7 +862,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replies.incrementAndGet()); Assert.assertTrue(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("500")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("500")); replyLatch.countDown(); } }); @@ -869,7 +875,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest final String pangram1 = "the quick brown fox jumps over the lazy dog"; final String pangram2 = "qualche vago ione tipo zolfo, bromo, sodio"; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -887,11 +893,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(2); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -905,7 +911,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replyFrames.incrementAndGet()); Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); Assert.assertTrue(replyHeaders.get("extra").value().contains("X")); replyLatch.countDown(); } @@ -937,7 +943,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final byte[] data = new byte[2048]; final CountDownLatch handlerLatch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -953,11 +959,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "GET"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "GET"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() @@ -971,7 +977,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest Assert.assertEquals(1, replyFrames.incrementAndGet()); Assert.assertFalse(replyInfo.isClose()); Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } @@ -994,7 +1000,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final byte[] data = new byte[2000]; final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -1030,11 +1036,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() { @@ -1042,7 +1048,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest public void onReply(Stream stream, ReplyInfo replyInfo) { Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }).get(5, TimeUnit.SECONDS); @@ -1057,7 +1063,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final byte[] data = new byte[2000]; final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -1093,11 +1099,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch replyLatch = new CountDownLatch(1); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() { @@ -1105,7 +1111,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest public void onReply(Stream stream, ReplyInfo replyInfo) { Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); replyLatch.countDown(); } }).get(5, TimeUnit.SECONDS); @@ -1121,7 +1127,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest { final byte[] data = new byte[1000]; final CountDownLatch latch = new CountDownLatch(1); - Session session = startClient(startHTTPServer(new AbstractHandler() + Session session = startClient(version(), startHTTPServer(version(), new AbstractHandler() { @Override public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) @@ -1166,11 +1172,11 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest }), null); Headers headers = new Headers(); - headers.put("method", "POST"); - headers.put("url", "/foo"); - headers.put("version", "HTTP/1.1"); - headers.put("scheme", "http"); - headers.put("host", "localhost:" + connector.getLocalPort()); + headers.put(HTTPSPDYHeader.METHOD.name(version()), "POST"); + headers.put(HTTPSPDYHeader.URI.name(version()), "/foo"); + headers.put(HTTPSPDYHeader.VERSION.name(version()), "HTTP/1.1"); + headers.put(HTTPSPDYHeader.SCHEME.name(version()), "http"); + headers.put(HTTPSPDYHeader.HOST.name(version()), "localhost:" + connector.getLocalPort()); final CountDownLatch responseLatch = new CountDownLatch(2); Stream stream = session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter() { @@ -1178,7 +1184,7 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest public void onReply(Stream stream, ReplyInfo replyInfo) { Headers replyHeaders = replyInfo.getHeaders(); - Assert.assertTrue(replyHeaders.get("status").value().contains("200")); + Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version())).value().contains("200")); responseLatch.countDown(); } diff --git a/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv3Test.java b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv3Test.java new file mode 100644 index 00000000000..bd7ee068850 --- /dev/null +++ b/jetty-spdy/spdy-jetty-http/src/test/java/org/eclipse/jetty/spdy/http/ServerHTTPSPDYv3Test.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2012 the original author or authors. + * + * 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 org.eclipse.jetty.spdy.http; + +import org.eclipse.jetty.spdy.api.SPDY; + +public class ServerHTTPSPDYv3Test extends ServerHTTPSPDYv2Test +{ + @Override + protected short version() + { + return SPDY.V3; + } +} diff --git a/jetty-spdy/spdy-jetty/src/main/java/org/eclipse/jetty/spdy/ServerSPDYAsyncConnectionFactory.java b/jetty-spdy/spdy-jetty/src/main/java/org/eclipse/jetty/spdy/ServerSPDYAsyncConnectionFactory.java index e5af7089521..0b0ae82b214 100644 --- a/jetty-spdy/spdy-jetty/src/main/java/org/eclipse/jetty/spdy/ServerSPDYAsyncConnectionFactory.java +++ b/jetty-spdy/spdy-jetty/src/main/java/org/eclipse/jetty/spdy/ServerSPDYAsyncConnectionFactory.java @@ -50,6 +50,11 @@ public class ServerSPDYAsyncConnectionFactory implements AsyncConnectionFactory this.listener = listener; } + public short getVersion() + { + return version; + } + @Override public AsyncConnection newAsyncConnection(SocketChannel channel, AsyncEndPoint endPoint, Object attachment) {