1 /* 2 * Copyright (C) 2012 Square, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.squareup.okhttp.internal.framed; 17 18 import java.util.Arrays; 19 20 /** 21 * Settings describe characteristics of the sending peer, which are used by the receiving peer. 22 * Settings are {@link FramedConnection connection} scoped. 23 */ 24 public final class Settings { 25 /** 26 * From the SPDY/3 and HTTP/2 specs, the default initial window size for all 27 * streams is 64 KiB. (Chrome 25 uses 10 MiB). 28 */ 29 static final int DEFAULT_INITIAL_WINDOW_SIZE = 64 * 1024; 30 31 /** Peer request to clear durable settings. */ 32 static final int FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1; 33 34 /** Sent by servers only. The peer requests this setting persisted for future connections. */ 35 static final int PERSIST_VALUE = 0x1; 36 /** Sent by clients only. The client is reminding the server of a persisted value. */ 37 static final int PERSISTED = 0x2; 38 39 /** spdy/3: Sender's estimate of max incoming kbps. */ 40 static final int UPLOAD_BANDWIDTH = 1; 41 /** HTTP/2: Size in bytes of the table used to decode the sender's header blocks. */ 42 static final int HEADER_TABLE_SIZE = 1; 43 /** spdy/3: Sender's estimate of max outgoing kbps. */ 44 static final int DOWNLOAD_BANDWIDTH = 2; 45 /** HTTP/2: The peer must not send a PUSH_PROMISE frame when this is 0. */ 46 static final int ENABLE_PUSH = 2; 47 /** spdy/3: Sender's estimate of millis between sending a request and receiving a response. */ 48 static final int ROUND_TRIP_TIME = 3; 49 /** Sender's maximum number of concurrent streams. */ 50 static final int MAX_CONCURRENT_STREAMS = 4; 51 /** spdy/3: Current CWND in Packets. */ 52 static final int CURRENT_CWND = 5; 53 /** HTTP/2: Size in bytes of the largest frame payload the sender will accept. */ 54 static final int MAX_FRAME_SIZE = 5; 55 /** spdy/3: Retransmission rate. Percentage */ 56 static final int DOWNLOAD_RETRANS_RATE = 6; 57 /** HTTP/2: Advisory only. Size in bytes of the largest header list the sender will accept. */ 58 static final int MAX_HEADER_LIST_SIZE = 6; 59 /** Window size in bytes. */ 60 static final int INITIAL_WINDOW_SIZE = 7; 61 /** spdy/3: Size of the client certificate vector. Unsupported. */ 62 static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8; 63 /** Flow control options. */ 64 static final int FLOW_CONTROL_OPTIONS = 10; 65 66 /** Total number of settings. */ 67 static final int COUNT = 10; 68 69 /** If set, flow control is disabled for streams directed to the sender of these settings. */ 70 static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1; 71 72 /** Bitfield of which flags that values. */ 73 private int set; 74 75 /** Bitfield of flags that have {@link #PERSIST_VALUE}. */ 76 private int persistValue; 77 78 /** Bitfield of flags that have {@link #PERSISTED}. */ 79 private int persisted; 80 81 /** Flag values. */ 82 private final int[] values = new int[COUNT]; 83 clear()84 void clear() { 85 set = persistValue = persisted = 0; 86 Arrays.fill(values, 0); 87 } 88 set(int id, int idFlags, int value)89 Settings set(int id, int idFlags, int value) { 90 if (id >= values.length) { 91 return this; // Discard unknown settings. 92 } 93 94 int bit = 1 << id; 95 set |= bit; 96 if ((idFlags & PERSIST_VALUE) != 0) { 97 persistValue |= bit; 98 } else { 99 persistValue &= ~bit; 100 } 101 if ((idFlags & PERSISTED) != 0) { 102 persisted |= bit; 103 } else { 104 persisted &= ~bit; 105 } 106 107 values[id] = value; 108 return this; 109 } 110 111 /** Returns true if a value has been assigned for the setting {@code id}. */ isSet(int id)112 boolean isSet(int id) { 113 int bit = 1 << id; 114 return (set & bit) != 0; 115 } 116 117 /** Returns the value for the setting {@code id}, or 0 if unset. */ get(int id)118 int get(int id) { 119 return values[id]; 120 } 121 122 /** Returns the flags for the setting {@code id}, or 0 if unset. */ flags(int id)123 int flags(int id) { 124 int result = 0; 125 if (isPersisted(id)) result |= Settings.PERSISTED; 126 if (persistValue(id)) result |= Settings.PERSIST_VALUE; 127 return result; 128 } 129 130 /** Returns the number of settings that have values assigned. */ size()131 int size() { 132 return Integer.bitCount(set); 133 } 134 135 /** spdy/3 only. */ getUploadBandwidth(int defaultValue)136 int getUploadBandwidth(int defaultValue) { 137 int bit = 1 << UPLOAD_BANDWIDTH; 138 return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue; 139 } 140 141 /** HTTP/2 only. Returns -1 if unset. */ getHeaderTableSize()142 int getHeaderTableSize() { 143 int bit = 1 << HEADER_TABLE_SIZE; 144 return (bit & set) != 0 ? values[HEADER_TABLE_SIZE] : -1; 145 } 146 147 /** spdy/3 only. */ getDownloadBandwidth(int defaultValue)148 int getDownloadBandwidth(int defaultValue) { 149 int bit = 1 << DOWNLOAD_BANDWIDTH; 150 return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue; 151 } 152 153 /** HTTP/2 only. */ 154 // TODO: honor this setting in HTTP/2. getEnablePush(boolean defaultValue)155 boolean getEnablePush(boolean defaultValue) { 156 int bit = 1 << ENABLE_PUSH; 157 return ((bit & set) != 0 ? values[ENABLE_PUSH] : defaultValue ? 1 : 0) == 1; 158 } 159 160 /** spdy/3 only. */ getRoundTripTime(int defaultValue)161 int getRoundTripTime(int defaultValue) { 162 int bit = 1 << ROUND_TRIP_TIME; 163 return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue; 164 } 165 166 // TODO: honor this setting in spdy/3 and HTTP/2. getMaxConcurrentStreams(int defaultValue)167 int getMaxConcurrentStreams(int defaultValue) { 168 int bit = 1 << MAX_CONCURRENT_STREAMS; 169 return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue; 170 } 171 172 /** spdy/3 only. */ getCurrentCwnd(int defaultValue)173 int getCurrentCwnd(int defaultValue) { 174 int bit = 1 << CURRENT_CWND; 175 return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue; 176 } 177 178 /** HTTP/2 only. */ getMaxFrameSize(int defaultValue)179 int getMaxFrameSize(int defaultValue) { 180 int bit = 1 << MAX_FRAME_SIZE; 181 return (bit & set) != 0 ? values[MAX_FRAME_SIZE] : defaultValue; 182 } 183 184 /** spdy/3 only. */ getDownloadRetransRate(int defaultValue)185 int getDownloadRetransRate(int defaultValue) { 186 int bit = 1 << DOWNLOAD_RETRANS_RATE; 187 return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue; 188 } 189 190 /** HTTP/2 only. */ getMaxHeaderListSize(int defaultValue)191 int getMaxHeaderListSize(int defaultValue) { 192 int bit = 1 << MAX_HEADER_LIST_SIZE; 193 return (bit & set) != 0 ? values[MAX_HEADER_LIST_SIZE] : defaultValue; 194 } 195 getInitialWindowSize(int defaultValue)196 int getInitialWindowSize(int defaultValue) { 197 int bit = 1 << INITIAL_WINDOW_SIZE; 198 return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue; 199 } 200 201 /** spdy/3 only. */ getClientCertificateVectorSize(int defaultValue)202 int getClientCertificateVectorSize(int defaultValue) { 203 int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE; 204 return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue; 205 } 206 207 // TODO: honor this setting in spdy/3 and HTTP/2. isFlowControlDisabled()208 boolean isFlowControlDisabled() { 209 int bit = 1 << FLOW_CONTROL_OPTIONS; 210 int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0; 211 return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0; 212 } 213 214 /** 215 * Returns true if this user agent should use this setting in future spdy/3 216 * connections to the same host. 217 */ persistValue(int id)218 boolean persistValue(int id) { 219 int bit = 1 << id; 220 return (persistValue & bit) != 0; 221 } 222 223 /** Returns true if this setting was persisted. */ isPersisted(int id)224 boolean isPersisted(int id) { 225 int bit = 1 << id; 226 return (persisted & bit) != 0; 227 } 228 229 /** 230 * Writes {@code other} into this. If any setting is populated by this and 231 * {@code other}, the value and flags from {@code other} will be kept. 232 */ merge(Settings other)233 void merge(Settings other) { 234 for (int i = 0; i < COUNT; i++) { 235 if (!other.isSet(i)) continue; 236 set(i, other.flags(i), other.get(i)); 237 } 238 } 239 } 240