1
16 package okhttp3.internal.http;
17
18 import java.io.IOException;
19 import java.util.List;
20 import java.util.concurrent.TimeUnit;
21 import javax.annotation.Nullable;
22 import okhttp3.Call;
23 import okhttp3.Connection;
24 import okhttp3.Interceptor;
25 import okhttp3.Request;
26 import okhttp3.Response;
27 import okhttp3.internal.connection.Exchange;
28 import okhttp3.internal.connection.Transmitter;
29
30 import static okhttp3.internal.Util.checkDuration;
31
32
39 public final class RealInterceptorChain implements Interceptor.Chain {
40 private final List<Interceptor> interceptors;
41 private final Transmitter transmitter;
42 private final @Nullable Exchange exchange;
43 private final int index;
44 private final Request request;
45 private final Call call;
46 private final int connectTimeout;
47 private final int readTimeout;
48 private final int writeTimeout;
49 private int calls;
50
51 public RealInterceptorChain(List<Interceptor> interceptors, Transmitter transmitter,
52 @Nullable Exchange exchange, int index, Request request, Call call,
53 int connectTimeout, int readTimeout, int writeTimeout) {
54 this.interceptors = interceptors;
55 this.transmitter = transmitter;
56 this.exchange = exchange;
57 this.index = index;
58 this.request = request;
59 this.call = call;
60 this.connectTimeout = connectTimeout;
61 this.readTimeout = readTimeout;
62 this.writeTimeout = writeTimeout;
63 }
64
65 @Override public @Nullable Connection connection() {
66 return exchange != null ? exchange.connection() : null;
67 }
68
69 @Override public int connectTimeoutMillis() {
70 return connectTimeout;
71 }
72
73 @Override public Interceptor.Chain withConnectTimeout(int timeout, TimeUnit unit) {
74 int millis = checkDuration("timeout", timeout, unit);
75 return new RealInterceptorChain(interceptors, transmitter, exchange, index, request, call,
76 millis, readTimeout, writeTimeout);
77 }
78
79 @Override public int readTimeoutMillis() {
80 return readTimeout;
81 }
82
83 @Override public Interceptor.Chain withReadTimeout(int timeout, TimeUnit unit) {
84 int millis = checkDuration("timeout", timeout, unit);
85 return new RealInterceptorChain(interceptors, transmitter, exchange, index, request, call,
86 connectTimeout, millis, writeTimeout);
87 }
88
89 @Override public int writeTimeoutMillis() {
90 return writeTimeout;
91 }
92
93 @Override public Interceptor.Chain withWriteTimeout(int timeout, TimeUnit unit) {
94 int millis = checkDuration("timeout", timeout, unit);
95 return new RealInterceptorChain(interceptors, transmitter, exchange, index, request, call,
96 connectTimeout, readTimeout, millis);
97 }
98
99 public Transmitter transmitter() {
100 return transmitter;
101 }
102
103 public Exchange exchange() {
104 if (exchange == null) throw new IllegalStateException();
105 return exchange;
106 }
107
108 @Override public Call call() {
109 return call;
110 }
111
112 @Override public Request request() {
113 return request;
114 }
115
116 @Override public Response proceed(Request request) throws IOException {
117 return proceed(request, transmitter, exchange);
118 }
119
120 public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
121 throws IOException {
122 if (index >= interceptors.size()) throw new AssertionError();
123
124 calls++;
125
126
127 if (this.exchange != null && !this.exchange.connection().supportsUrl(request.url())) {
128 throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
129 + " must retain the same host and port");
130 }
131
132
133 if (this.exchange != null && calls > 1) {
134 throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
135 + " must call proceed() exactly once");
136 }
137
138
139 RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
140 index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
141 Interceptor interceptor = interceptors.get(index);
142 Response response = interceptor.intercept(next);
143
144
145 if (exchange != null && index + 1 < interceptors.size() && next.calls != 1) {
146 throw new IllegalStateException("network interceptor " + interceptor
147 + " must call proceed() exactly once");
148 }
149
150
151 if (response == null) {
152 throw new NullPointerException("interceptor " + interceptor + " returned null");
153 }
154
155 if (response.body() == null) {
156 throw new IllegalStateException(
157 "interceptor " + interceptor + " returned a response with no body");
158 }
159
160 return response;
161 }
162 }
163