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 */
16package com.squareup.okhttp.internal.spdy;
17
18import 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 */
24final 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