blob: bb67b8311adeed4a84c852e6e7815aade5eba1bb [file] [log] [blame]
/*
* Copyright (C) 2012 Square, Inc.
*
* 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 com.squareup.okhttp.internal.spdy;
import java.util.Arrays;
/**
* Settings describe characteristics of the sending peer, which are used by the receiving peer.
* Settings are {@link com.squareup.okhttp.internal.spdy.SpdyConnection connection} scoped.
*/
public final class Settings {
/**
* From the SPDY/3 and HTTP/2 specs, the default initial window size for all
* streams is 64 KiB. (Chrome 25 uses 10 MiB).
*/
static final int DEFAULT_INITIAL_WINDOW_SIZE = 64 * 1024;
/** Peer request to clear durable settings. */
static final int FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1;
/** Sent by servers only. The peer requests this setting persisted for future connections. */
static final int PERSIST_VALUE = 0x1;
/** Sent by clients only. The client is reminding the server of a persisted value. */
static final int PERSISTED = 0x2;
/** spdy/3: Sender's estimate of max incoming kbps. */
static final int UPLOAD_BANDWIDTH = 1;
/** HTTP/2: Size in bytes of the table used to decode the sender's header blocks. */
static final int HEADER_TABLE_SIZE = 1;
/** spdy/3: Sender's estimate of max outgoing kbps. */
static final int DOWNLOAD_BANDWIDTH = 2;
/** HTTP/2: The peer must not send a PUSH_PROMISE frame when this is 0. */
static final int ENABLE_PUSH = 2;
/** spdy/3: Sender's estimate of millis between sending a request and receiving a response. */
static final int ROUND_TRIP_TIME = 3;
/** Sender's maximum number of concurrent streams. */
static final int MAX_CONCURRENT_STREAMS = 4;
/** spdy/3: Current CWND in Packets. */
static final int CURRENT_CWND = 5;
/** HTTP/2: Size in bytes of the largest frame payload the sender will accept. */
static final int MAX_FRAME_SIZE = 5;
/** spdy/3: Retransmission rate. Percentage */
static final int DOWNLOAD_RETRANS_RATE = 6;
/** HTTP/2: Advisory only. Size in bytes of the largest header list the sender will accept. */
static final int MAX_HEADER_LIST_SIZE = 6;
/** Window size in bytes. */
static final int INITIAL_WINDOW_SIZE = 7;
/** spdy/3: Size of the client certificate vector. Unsupported. */
static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8;
/** Flow control options. */
static final int FLOW_CONTROL_OPTIONS = 10;
/** Total number of settings. */
static final int COUNT = 10;
/** If set, flow control is disabled for streams directed to the sender of these settings. */
static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1;
/** Bitfield of which flags that values. */
private int set;
/** Bitfield of flags that have {@link #PERSIST_VALUE}. */
private int persistValue;
/** Bitfield of flags that have {@link #PERSISTED}. */
private int persisted;
/** Flag values. */
private final int[] values = new int[COUNT];
void clear() {
set = persistValue = persisted = 0;
Arrays.fill(values, 0);
}
Settings set(int id, int idFlags, int value) {
if (id >= values.length) {
return this; // Discard unknown settings.
}
int bit = 1 << id;
set |= bit;
if ((idFlags & PERSIST_VALUE) != 0) {
persistValue |= bit;
} else {
persistValue &= ~bit;
}
if ((idFlags & PERSISTED) != 0) {
persisted |= bit;
} else {
persisted &= ~bit;
}
values[id] = value;
return this;
}
/** Returns true if a value has been assigned for the setting {@code id}. */
boolean isSet(int id) {
int bit = 1 << id;
return (set & bit) != 0;
}
/** Returns the value for the setting {@code id}, or 0 if unset. */
int get(int id) {
return values[id];
}
/** Returns the flags for the setting {@code id}, or 0 if unset. */
int flags(int id) {
int result = 0;
if (isPersisted(id)) result |= Settings.PERSISTED;
if (persistValue(id)) result |= Settings.PERSIST_VALUE;
return result;
}
/** Returns the number of settings that have values assigned. */
int size() {
return Integer.bitCount(set);
}
/** spdy/3 only. */
int getUploadBandwidth(int defaultValue) {
int bit = 1 << UPLOAD_BANDWIDTH;
return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue;
}
/** HTTP/2 only. Returns -1 if unset. */
int getHeaderTableSize() {
int bit = 1 << HEADER_TABLE_SIZE;
return (bit & set) != 0 ? values[HEADER_TABLE_SIZE] : -1;
}
/** spdy/3 only. */
int getDownloadBandwidth(int defaultValue) {
int bit = 1 << DOWNLOAD_BANDWIDTH;
return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue;
}
/** HTTP/2 only. */
// TODO: honor this setting in HTTP/2.
boolean getEnablePush(boolean defaultValue) {
int bit = 1 << ENABLE_PUSH;
return ((bit & set) != 0 ? values[ENABLE_PUSH] : defaultValue ? 1 : 0) == 1;
}
/** spdy/3 only. */
int getRoundTripTime(int defaultValue) {
int bit = 1 << ROUND_TRIP_TIME;
return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue;
}
// TODO: honor this setting in spdy/3 and HTTP/2.
int getMaxConcurrentStreams(int defaultValue) {
int bit = 1 << MAX_CONCURRENT_STREAMS;
return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue;
}
/** spdy/3 only. */
int getCurrentCwnd(int defaultValue) {
int bit = 1 << CURRENT_CWND;
return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue;
}
/** HTTP/2 only. */
int getMaxFrameSize(int defaultValue) {
int bit = 1 << MAX_FRAME_SIZE;
return (bit & set) != 0 ? values[MAX_FRAME_SIZE] : defaultValue;
}
/** spdy/3 only. */
int getDownloadRetransRate(int defaultValue) {
int bit = 1 << DOWNLOAD_RETRANS_RATE;
return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue;
}
/** HTTP/2 only. */
int getMaxHeaderListSize(int defaultValue) {
int bit = 1 << MAX_HEADER_LIST_SIZE;
return (bit & set) != 0 ? values[MAX_HEADER_LIST_SIZE] : defaultValue;
}
int getInitialWindowSize(int defaultValue) {
int bit = 1 << INITIAL_WINDOW_SIZE;
return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue;
}
/** spdy/3 only. */
int getClientCertificateVectorSize(int defaultValue) {
int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE;
return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue;
}
// TODO: honor this setting in spdy/3 and HTTP/2.
boolean isFlowControlDisabled() {
int bit = 1 << FLOW_CONTROL_OPTIONS;
int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0;
return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0;
}
/**
* Returns true if this user agent should use this setting in future spdy/3
* connections to the same host.
*/
boolean persistValue(int id) {
int bit = 1 << id;
return (persistValue & bit) != 0;
}
/** Returns true if this setting was persisted. */
boolean isPersisted(int id) {
int bit = 1 << id;
return (persisted & bit) != 0;
}
/**
* Writes {@code other} into this. If any setting is populated by this and
* {@code other}, the value and flags from {@code other} will be kept.
*/
void merge(Settings other) {
for (int i = 0; i < COUNT; i++) {
if (!other.isSet(i)) continue;
set(i, other.flags(i), other.get(i));
}
}
}