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.spdy; 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 com.squareup.okhttp.internal.spdy.SpdyConnection connection} scoped. 23 */ 24 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: An endpoint 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 /** spdy/3: Retransmission rate. Percentage */ 54 static final int DOWNLOAD_RETRANS_RATE = 6; 55 /** Window size in bytes. */ 56 static final int INITIAL_WINDOW_SIZE = 7; 57 /** spdy/3: Window size in bytes. */ 58 static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8; 59 /** Flow control options. */ 60 static final int FLOW_CONTROL_OPTIONS = 10; 61 62 /** Total number of settings. */ 63 static final int COUNT = 10; 64 65 /** If set, flow control is disabled for streams directed to the sender of these settings. */ 66 static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1; 67 68 /** Bitfield of which flags that values. */ 69 private int set; 70 71 /** Bitfield of flags that have {@link #PERSIST_VALUE}. */ 72 private int persistValue; 73 74 /** Bitfield of flags that have {@link #PERSISTED}. */ 75 private int persisted; 76 77 /** Flag values. */ 78 private final int[] values = new int[COUNT]; 79 80 void clear() { 81 set = persistValue = persisted = 0; 82 Arrays.fill(values, 0); 83 } 84 85 Settings set(int id, int idFlags, int value) { 86 if (id >= values.length) { 87 return this; // Discard unknown settings. 88 } 89 90 int bit = 1 << id; 91 set |= bit; 92 if ((idFlags & PERSIST_VALUE) != 0) { 93 persistValue |= bit; 94 } else { 95 persistValue &= ~bit; 96 } 97 if ((idFlags & PERSISTED) != 0) { 98 persisted |= bit; 99 } else { 100 persisted &= ~bit; 101 } 102 103 values[id] = value; 104 return this; 105 } 106 107 /** Returns true if a value has been assigned for the setting {@code id}. */ 108 boolean isSet(int id) { 109 int bit = 1 << id; 110 return (set & bit) != 0; 111 } 112 113 /** Returns the value for the setting {@code id}, or 0 if unset. */ 114 int get(int id) { 115 return values[id]; 116 } 117 118 /** Returns the flags for the setting {@code id}, or 0 if unset. */ 119 int flags(int id) { 120 int result = 0; 121 if (isPersisted(id)) result |= Settings.PERSISTED; 122 if (persistValue(id)) result |= Settings.PERSIST_VALUE; 123 return result; 124 } 125 126 /** Returns the number of settings that have values assigned. */ 127 int size() { 128 return Integer.bitCount(set); 129 } 130 131 /** spdy/3 only. */ 132 int getUploadBandwidth(int defaultValue) { 133 int bit = 1 << UPLOAD_BANDWIDTH; 134 return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue; 135 } 136 137 /** http/2 only. Returns -1 if unset. */ 138 int getHeaderTableSize() { 139 int bit = 1 << HEADER_TABLE_SIZE; 140 return (bit & set) != 0 ? values[HEADER_TABLE_SIZE] : -1; 141 } 142 143 /** spdy/3 only. */ 144 int getDownloadBandwidth(int defaultValue) { 145 int bit = 1 << DOWNLOAD_BANDWIDTH; 146 return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue; 147 } 148 149 /** http/2 only. */ 150 // TODO: honor this setting in http/2. 151 boolean getEnablePush(boolean defaultValue) { 152 int bit = 1 << ENABLE_PUSH; 153 return ((bit & set) != 0 ? values[ENABLE_PUSH] : defaultValue ? 1 : 0) == 1; 154 } 155 156 /** spdy/3 only. */ 157 int getRoundTripTime(int defaultValue) { 158 int bit = 1 << ROUND_TRIP_TIME; 159 return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue; 160 } 161 162 // TODO: honor this setting in spdy/3 and http/2. 163 int getMaxConcurrentStreams(int defaultValue) { 164 int bit = 1 << MAX_CONCURRENT_STREAMS; 165 return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue; 166 } 167 168 /** spdy/3 only. */ 169 int getCurrentCwnd(int defaultValue) { 170 int bit = 1 << CURRENT_CWND; 171 return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue; 172 } 173 174 /** spdy/3 only. */ 175 int getDownloadRetransRate(int defaultValue) { 176 int bit = 1 << DOWNLOAD_RETRANS_RATE; 177 return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue; 178 } 179 180 int getInitialWindowSize(int defaultValue) { 181 int bit = 1 << INITIAL_WINDOW_SIZE; 182 return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue; 183 } 184 185 /** spdy/3 only. */ 186 int getClientCertificateVectorSize(int defaultValue) { 187 int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE; 188 return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue; 189 } 190 191 // TODO: honor this setting in spdy/3 and http/2. 192 boolean isFlowControlDisabled() { 193 int bit = 1 << FLOW_CONTROL_OPTIONS; 194 int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0; 195 return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0; 196 } 197 198 /** 199 * Returns true if this user agent should use this setting in future spdy/3 200 * connections to the same host. 201 */ 202 boolean persistValue(int id) { 203 int bit = 1 << id; 204 return (persistValue & bit) != 0; 205 } 206 207 /** Returns true if this setting was persisted. */ 208 boolean isPersisted(int id) { 209 int bit = 1 << id; 210 return (persisted & bit) != 0; 211 } 212 213 /** 214 * Writes {@code other} into this. If any setting is populated by this and 215 * {@code other}, the value and flags from {@code other} will be kept. 216 */ 217 void merge(Settings other) { 218 for (int i = 0; i < COUNT; i++) { 219 if (!other.isSet(i)) continue; 220 set(i, other.flags(i), other.get(i)); 221 } 222 } 223 } 224