1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.net.http; 27 28 import java.io.IOException; 29 import java.nio.ByteBuffer; 30 31 /** 32 * When sending a frame, the length field must be set in sub-class 33 * by calling computeLength() 34 */ 35 abstract class Http2Frame { 36 37 int length = -1; 38 int type; 39 int streamid; 40 int flags; 41 42 // called when reading in only 43 void initCommon(int length, int type, int streamid, int flags) { 44 this.length = length; 45 this.type = type; 46 this.streamid = streamid; 47 this.flags = flags; 48 } 49 50 public int length() { 51 return length; 52 } 53 54 public int type() { 55 return type; 56 } 57 58 public int streamid() { 59 return streamid; 60 } 61 62 public void setFlag(int flag) { 63 flags |= flag; 64 } 65 66 public void setFlags(int flags) { 67 this.flags = flags; 68 } 69 70 public int getFlags() { 71 return flags; 72 } 73 74 public boolean getFlag(int flag) { 75 return (flags & flag) != 0; 76 } 77 78 public void clearFlag(int flag) { 79 flags &= 0xffffffff ^ flag; 80 } 81 82 public void streamid(int streamid) { 83 this.streamid = streamid; 84 } 85 86 abstract void readIncomingImpl(ByteBufferConsumer bc) throws IOException; 87 88 /** 89 * assume given array contains at least one complete frame. 90 */ 91 static Http2Frame readIncoming(ByteBufferConsumer bc) throws IOException { 92 int x = bc.getInt(); 93 int length = x >> 8; 94 int type = x & 0xff; 95 int flags = bc.getByte(); 96 int streamid = bc.getInt(); 97 Http2Frame f = null; 98 switch (type) { 99 case DataFrame.TYPE: 100 f = new DataFrame(); 101 break; 102 case HeadersFrame.TYPE: 103 f = new HeadersFrame(); 104 break; 105 case ContinuationFrame.TYPE: 106 f = new ContinuationFrame(); 107 break; 108 case ResetFrame.TYPE: 109 f = new ResetFrame(); 110 break; 111 case PriorityFrame.TYPE: 112 f = new PriorityFrame(); 113 break; 114 case SettingsFrame.TYPE: 115 f = new SettingsFrame(); 116 break; 117 case GoAwayFrame.TYPE: 118 f = new GoAwayFrame(); 119 break; 120 case PingFrame.TYPE: 121 f = new PingFrame(); 122 break; 123 case PushPromiseFrame.TYPE: 124 f = new PushPromiseFrame(); 125 break; 126 case WindowUpdateFrame.TYPE: 127 f = new WindowUpdateFrame(); 128 break; 129 default: 130 String msg = Integer.toString(type); 131 throw new IOException("unknown frame type " + msg); 132 } 133 f.initCommon(length, type, streamid, flags); 134 f.readIncomingImpl(bc); 135 return f; 136 } 137 138 public String typeAsString() { 139 return asString(this.type); 140 } 141 142 public static String asString(int type) { 143 switch (type) { 144 case DataFrame.TYPE: 145 return "DATA"; 146 case HeadersFrame.TYPE: 147 return "HEADERS"; 148 case ContinuationFrame.TYPE: 149 return "CONTINUATION"; 150 case ResetFrame.TYPE: 151 return "RESET"; 152 case PriorityFrame.TYPE: 153 return "PRIORITY"; 154 case SettingsFrame.TYPE: 155 return "SETTINGS"; 156 case GoAwayFrame.TYPE: 157 return "GOAWAY"; 158 case PingFrame.TYPE: 159 return "PING"; 160 case PushPromiseFrame.TYPE: 161 return "PUSH_PROMISE"; 162 case WindowUpdateFrame.TYPE: 163 return "WINDOW_UPDATE"; 164 default: 165 return "UNKNOWN"; 166 } 167 } 168 169 @Override 170 public String toString() { 171 StringBuilder sb = new StringBuilder(); 172 sb.append(typeAsString()) 173 .append(": length=") 174 .append(Integer.toString(length)) 175 .append(", streamid=") 176 .append(streamid) 177 .append(", flags="); 178 179 int f = flags; 180 int i = 0; 181 if (f == 0) { 182 sb.append("0 "); 183 } else { 184 while (f != 0) { 185 if ((f & 1) == 1) { 186 sb.append(flagAsString(1 << i)) 187 .append(' '); 188 } 189 f = f >> 1; 190 i++; 191 } 192 } 193 return sb.toString(); 194 } 195 196 // Override 197 String flagAsString(int f) { 198 return "unknown"; 199 } 200 201 abstract void computeLength(); 202 203 void writeOutgoing(ByteBufferGenerator bg) { 204 if (length == -1) { 205 throw new InternalError("Length not set on outgoing frame"); 206 } 207 ByteBuffer buf = bg.getBuffer(9); 208 int x = (length << 8) + type; 209 buf.putInt(x); 210 buf.put((byte)flags); 211 buf.putInt(streamid); 212 } 213 }