39 import java.util.Objects; |
39 import java.util.Objects; |
40 import java.util.Optional; |
40 import java.util.Optional; |
41 import java.net.http.HttpClient; |
41 import java.net.http.HttpClient; |
42 import java.net.http.HttpHeaders; |
42 import java.net.http.HttpHeaders; |
43 import java.net.http.HttpRequest; |
43 import java.net.http.HttpRequest; |
44 import jdk.internal.net.http.common.HttpHeadersImpl; |
44 import jdk.internal.net.http.common.HttpHeadersBuilder; |
45 import jdk.internal.net.http.common.Utils; |
45 import jdk.internal.net.http.common.Utils; |
46 import jdk.internal.net.http.websocket.WebSocketRequest; |
46 import jdk.internal.net.http.websocket.WebSocketRequest; |
47 |
47 |
48 import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS; |
48 import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS; |
49 |
49 |
50 class HttpRequestImpl extends HttpRequest implements WebSocketRequest { |
50 public class HttpRequestImpl extends HttpRequest implements WebSocketRequest { |
51 |
51 |
52 private final HttpHeaders userHeaders; |
52 private final HttpHeaders userHeaders; |
53 private final HttpHeadersImpl systemHeaders; |
53 private final HttpHeadersBuilder systemHeadersBuilder; |
54 private final URI uri; |
54 private final URI uri; |
55 private volatile Proxy proxy; // ensure safe publishing |
55 private volatile Proxy proxy; // ensure safe publishing |
56 private final InetSocketAddress authority; // only used when URI not specified |
56 private final InetSocketAddress authority; // only used when URI not specified |
57 private final String method; |
57 private final String method; |
58 final BodyPublisher requestPublisher; |
58 final BodyPublisher requestPublisher; |
76 * Creates an HttpRequestImpl from the given builder. |
76 * Creates an HttpRequestImpl from the given builder. |
77 */ |
77 */ |
78 public HttpRequestImpl(HttpRequestBuilderImpl builder) { |
78 public HttpRequestImpl(HttpRequestBuilderImpl builder) { |
79 String method = builder.method(); |
79 String method = builder.method(); |
80 this.method = method == null ? "GET" : method; |
80 this.method = method == null ? "GET" : method; |
81 this.userHeaders = ImmutableHeaders.of(builder.headers().map(), ALLOWED_HEADERS); |
81 this.userHeaders = HttpHeaders.of(builder.headersBuilder().map(), ALLOWED_HEADERS); |
82 this.systemHeaders = new HttpHeadersImpl(); |
82 this.systemHeadersBuilder = new HttpHeadersBuilder(); |
83 this.uri = builder.uri(); |
83 this.uri = builder.uri(); |
84 assert uri != null; |
84 assert uri != null; |
85 this.proxy = null; |
85 this.proxy = null; |
86 this.expectContinue = builder.expectContinue(); |
86 this.expectContinue = builder.expectContinue(); |
87 this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https"); |
87 this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https"); |
104 + "\""); |
104 + "\""); |
105 URI requestURI = Objects.requireNonNull(request.uri(), |
105 URI requestURI = Objects.requireNonNull(request.uri(), |
106 "uri must be non null"); |
106 "uri must be non null"); |
107 Duration timeout = request.timeout().orElse(null); |
107 Duration timeout = request.timeout().orElse(null); |
108 this.method = method == null ? "GET" : method; |
108 this.method = method == null ? "GET" : method; |
109 this.userHeaders = ImmutableHeaders.validate(request.headers()); |
109 this.userHeaders = HttpHeaders.of(request.headers().map(), Utils.VALIDATE_USER_HEADER); |
110 if (request instanceof HttpRequestImpl) { |
110 if (request instanceof HttpRequestImpl) { |
111 // all cases exception WebSocket should have a new system headers |
111 // all cases exception WebSocket should have a new system headers |
112 this.isWebSocket = ((HttpRequestImpl) request).isWebSocket; |
112 this.isWebSocket = ((HttpRequestImpl) request).isWebSocket; |
113 if (isWebSocket) { |
113 if (isWebSocket) { |
114 this.systemHeaders = ((HttpRequestImpl) request).systemHeaders; |
114 this.systemHeadersBuilder = ((HttpRequestImpl)request).systemHeadersBuilder; |
115 } else { |
115 } else { |
116 this.systemHeaders = new HttpHeadersImpl(); |
116 this.systemHeadersBuilder = new HttpHeadersBuilder(); |
117 } |
117 } |
118 } else { |
118 } else { |
119 HttpRequestBuilderImpl.checkURI(requestURI); |
119 HttpRequestBuilderImpl.checkURI(requestURI); |
120 checkTimeout(timeout); |
120 checkTimeout(timeout); |
121 this.systemHeaders = new HttpHeadersImpl(); |
121 this.systemHeadersBuilder = new HttpHeadersBuilder(); |
122 } |
122 } |
123 this.systemHeaders.setHeader("User-Agent", USER_AGENT); |
123 if (!userHeaders.firstValue("User-Agent").isPresent()) { |
|
124 this.systemHeadersBuilder.setHeader("User-Agent", USER_AGENT); |
|
125 } |
124 this.uri = requestURI; |
126 this.uri = requestURI; |
125 if (isWebSocket) { |
127 if (isWebSocket) { |
126 // WebSocket determines and sets the proxy itself |
128 // WebSocket determines and sets the proxy itself |
127 this.proxy = ((HttpRequestImpl) request).proxy; |
129 this.proxy = ((HttpRequestImpl) request).proxy; |
128 } else { |
130 } else { |
167 HttpRequestImpl other) { |
169 HttpRequestImpl other) { |
168 assert method == null || Utils.isValidName(method); |
170 assert method == null || Utils.isValidName(method); |
169 this.method = method == null? "GET" : method; |
171 this.method = method == null? "GET" : method; |
170 this.userHeaders = other.userHeaders; |
172 this.userHeaders = other.userHeaders; |
171 this.isWebSocket = other.isWebSocket; |
173 this.isWebSocket = other.isWebSocket; |
172 this.systemHeaders = new HttpHeadersImpl(); |
174 this.systemHeadersBuilder = new HttpHeadersBuilder(); |
173 this.systemHeaders.setHeader("User-Agent", USER_AGENT); |
175 if (!userHeaders.firstValue("User-Agent").isPresent()) { |
|
176 this.systemHeadersBuilder.setHeader("User-Agent", USER_AGENT); |
|
177 } |
174 this.uri = uri; |
178 this.uri = uri; |
175 this.proxy = other.proxy; |
179 this.proxy = other.proxy; |
176 this.expectContinue = other.expectContinue; |
180 this.expectContinue = other.expectContinue; |
177 this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https"); |
181 this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https"); |
178 this.requestPublisher = other.requestPublisher; // may be null |
182 this.requestPublisher = other.requestPublisher; // may be null |
187 // TODO: isWebSocket flag is not specified, but the assumption is that |
191 // TODO: isWebSocket flag is not specified, but the assumption is that |
188 // such a request will never be made on a connection that will be returned |
192 // such a request will never be made on a connection that will be returned |
189 // to the connection pool (we might need to revisit this constructor later) |
193 // to the connection pool (we might need to revisit this constructor later) |
190 assert "CONNECT".equalsIgnoreCase(method); |
194 assert "CONNECT".equalsIgnoreCase(method); |
191 this.method = method; |
195 this.method = method; |
192 this.systemHeaders = new HttpHeadersImpl(); |
196 this.systemHeadersBuilder = new HttpHeadersBuilder(); |
193 this.userHeaders = ImmutableHeaders.of(headers); |
197 this.userHeaders = headers; |
194 this.uri = URI.create("socket://" + authority.getHostString() + ":" |
198 this.uri = URI.create("socket://" + authority.getHostString() + ":" |
195 + Integer.toString(authority.getPort()) + "/"); |
199 + Integer.toString(authority.getPort()) + "/"); |
196 this.proxy = null; |
200 this.proxy = null; |
197 this.requestPublisher = null; |
201 this.requestPublisher = null; |
198 this.authority = authority; |
202 this.authority = authority; |
216 * Creates a HttpRequestImpl from the given set of Headers and the associated |
220 * Creates a HttpRequestImpl from the given set of Headers and the associated |
217 * "parent" request. Fields not taken from the headers are taken from the |
221 * "parent" request. Fields not taken from the headers are taken from the |
218 * parent. |
222 * parent. |
219 */ |
223 */ |
220 static HttpRequestImpl createPushRequest(HttpRequestImpl parent, |
224 static HttpRequestImpl createPushRequest(HttpRequestImpl parent, |
221 HttpHeadersImpl headers) |
225 HttpHeaders headers) |
222 throws IOException |
226 throws IOException |
223 { |
227 { |
224 return new HttpRequestImpl(parent, headers); |
228 return new HttpRequestImpl(parent, headers); |
225 } |
229 } |
226 |
230 |
227 // only used for push requests |
231 // only used for push requests |
228 private HttpRequestImpl(HttpRequestImpl parent, HttpHeadersImpl headers) |
232 private HttpRequestImpl(HttpRequestImpl parent, HttpHeaders headers) |
229 throws IOException |
233 throws IOException |
230 { |
234 { |
231 this.method = headers.firstValue(":method") |
235 this.method = headers.firstValue(":method") |
232 .orElseThrow(() -> new IOException("No method in Push Promise")); |
236 .orElseThrow(() -> new IOException("No method in Push Promise")); |
233 String path = headers.firstValue(":path") |
237 String path = headers.firstValue(":path") |
238 .orElseThrow(() -> new IOException("No authority in Push Promise")); |
242 .orElseThrow(() -> new IOException("No authority in Push Promise")); |
239 StringBuilder sb = new StringBuilder(); |
243 StringBuilder sb = new StringBuilder(); |
240 sb.append(scheme).append("://").append(authority).append(path); |
244 sb.append(scheme).append("://").append(authority).append(path); |
241 this.uri = URI.create(sb.toString()); |
245 this.uri = URI.create(sb.toString()); |
242 this.proxy = null; |
246 this.proxy = null; |
243 this.userHeaders = ImmutableHeaders.of(headers.map(), ALLOWED_HEADERS); |
247 this.userHeaders = HttpHeaders.of(headers.map(), ALLOWED_HEADERS); |
244 this.systemHeaders = parent.systemHeaders; |
248 this.systemHeadersBuilder = parent.systemHeadersBuilder; |
245 this.expectContinue = parent.expectContinue; |
249 this.expectContinue = parent.expectContinue; |
246 this.secure = parent.secure; |
250 this.secure = parent.secure; |
247 this.requestPublisher = parent.requestPublisher; |
251 this.requestPublisher = parent.requestPublisher; |
248 this.acc = parent.acc; |
252 this.acc = parent.acc; |
249 this.timeout = parent.timeout; |
253 this.timeout = parent.timeout; |
262 } |
266 } |
263 |
267 |
264 InetSocketAddress authority() { return authority; } |
268 InetSocketAddress authority() { return authority; } |
265 |
269 |
266 void setH2Upgrade(Http2ClientImpl h2client) { |
270 void setH2Upgrade(Http2ClientImpl h2client) { |
267 systemHeaders.setHeader("Connection", "Upgrade, HTTP2-Settings"); |
271 systemHeadersBuilder.setHeader("Connection", "Upgrade, HTTP2-Settings"); |
268 systemHeaders.setHeader("Upgrade", "h2c"); |
272 systemHeadersBuilder.setHeader("Upgrade", "h2c"); |
269 systemHeaders.setHeader("HTTP2-Settings", h2client.getSettingsString()); |
273 systemHeadersBuilder.setHeader("HTTP2-Settings", h2client.getSettingsString()); |
270 } |
274 } |
271 |
275 |
272 @Override |
276 @Override |
273 public boolean expectContinue() { return expectContinue; } |
277 public boolean expectContinue() { return expectContinue; } |
274 |
278 |
330 return timeout == null ? Optional.empty() : Optional.of(timeout); |
334 return timeout == null ? Optional.empty() : Optional.of(timeout); |
331 } |
335 } |
332 |
336 |
333 HttpHeaders getUserHeaders() { return userHeaders; } |
337 HttpHeaders getUserHeaders() { return userHeaders; } |
334 |
338 |
335 HttpHeadersImpl getSystemHeaders() { return systemHeaders; } |
339 HttpHeadersBuilder getSystemHeadersBuilder() { return systemHeadersBuilder; } |
336 |
340 |
337 @Override |
341 @Override |
338 public Optional<HttpClient.Version> version() { return version; } |
342 public Optional<HttpClient.Version> version() { return version; } |
339 |
343 |
340 void addSystemHeader(String name, String value) { |
344 void addSystemHeader(String name, String value) { |
341 systemHeaders.addHeader(name, value); |
345 systemHeadersBuilder.addHeader(name, value); |
342 } |
346 } |
343 |
347 |
344 @Override |
348 @Override |
345 public void setSystemHeader(String name, String value) { |
349 public void setSystemHeader(String name, String value) { |
346 systemHeaders.setHeader(name, value); |
350 systemHeadersBuilder.setHeader(name, value); |
347 } |
351 } |
348 |
352 |
349 InetSocketAddress getAddress() { |
353 InetSocketAddress getAddress() { |
350 URI uri = uri(); |
354 URI uri = uri(); |
351 if (uri == null) { |
355 if (uri == null) { |