13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/* 23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2014 Square, Inc. 33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License. 63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at 73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software 113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and 143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License. 153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage com.squareup.okhttp.internal.spdy; 173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.Util; 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.IOException; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.ByteString; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport okio.OkBuffer; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.Test; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertEquals; 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.fail; 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic class Spdy3Test { 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static final int expectedStreamId = 15; 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void tooLargeDataFrame() throws IOException { 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sendDataFrame(new OkBuffer().write(new byte[0x1000000])); 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IllegalArgumentException e) { 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("FRAME_TOO_LARGE max size is 16Mib: " + 0x1000000L, e.getMessage()); 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void badWindowSizeIncrement() throws IOException { 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller windowUpdate(0); 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IllegalArgumentException e) { 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("windowSizeIncrement must be between 1 and 0x7fffffff: 0", e.getMessage()); 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller windowUpdate(0x80000000L); 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fail(); 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (IllegalArgumentException e) { 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("windowSizeIncrement must be between 1 and 0x7fffffff: 2147483648", 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller e.getMessage()); 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void goAwayRoundTrip() throws IOException { 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer frame = new OkBuffer(); 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller final ErrorCode expectedError = ErrorCode.PROTOCOL_ERROR; 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Compose the expected GOAWAY frame without debug data 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // |C| Version(15bits) | Type(16bits) | 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller frame.writeInt(0x80000000 | (Spdy3.VERSION & 0x7fff) << 16 | Spdy3.TYPE_GOAWAY & 0xffff); 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // | Flags (8) | Length (24 bits) | 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller frame.writeInt(8); // no flags and length is 8. 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller frame.writeInt(expectedStreamId); // last good stream. 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller frame.writeInt(expectedError.spdyGoAwayCode); 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Check writer sends the same bytes. 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(frame, sendGoAway(expectedStreamId, expectedError, Util.EMPTY_BYTE_ARRAY)); 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // SPDY/3 does not send debug data, so bytes should be same! 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(frame, sendGoAway(expectedStreamId, expectedError, new byte[8])); 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller FrameReader fr = new Spdy3.Reader(frame, false); 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller fr.nextFrame(new BaseTestHandler() { // Consume the goAway frame. 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void goAway( 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int lastGoodStreamId, ErrorCode errorCode, ByteString debugData) { 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(expectedStreamId, lastGoodStreamId); 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(expectedError, errorCode); 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, debugData.size()); 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller }); 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private void sendDataFrame(OkBuffer source) throws IOException { 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Spdy3.Writer writer = new Spdy3.Writer(new OkBuffer(), true); 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller writer.sendDataFrame(expectedStreamId, 0, source, (int) source.size()); 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private void windowUpdate(long increment) throws IOException { 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller new Spdy3.Writer(new OkBuffer(), true).windowUpdate(expectedStreamId, increment); 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private OkBuffer sendGoAway(int lastGoodStreamId, ErrorCode errorCode, byte[] debugData) 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller throws IOException { 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller OkBuffer out = new OkBuffer(); 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller new Spdy3.Writer(out, true).goAway(lastGoodStreamId, errorCode, debugData); 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return out; 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 102