source: josm/trunk/src/org/openstreetmap/josm/tools/Http1Client.java@ 15229

Last change on this file since 15229 was 15229, checked in by Don-vip, 5 years ago

see #17861 - Refactor HTTP client to support HTTP/2 in a new plugin requiring Java 11

File size: 7.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.io.BufferedOutputStream;
5import java.io.ByteArrayInputStream;
6import java.io.IOException;
7import java.io.InputStream;
8import java.io.OutputStream;
9import java.net.HttpURLConnection;
10import java.net.URL;
11import java.util.Collections;
12import java.util.List;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Optional;
16import java.util.TreeMap;
17
18import org.openstreetmap.josm.data.Version;
19import org.openstreetmap.josm.gui.progress.ProgressMonitor;
20import org.openstreetmap.josm.io.ProgressOutputStream;
21
22/**
23 * Provides a uniform access for a HTTP/HTTPS 1.0/1.1 server.
24 * @since 15229
25 */
26public final class Http1Client extends HttpClient {
27
28 private HttpURLConnection connection; // to allow disconnecting before `response` is set
29
30 /**
31 * Constructs a new {@code Http1Client}.
32 * @param url URL to access
33 * @param requestMethod HTTP request method (GET, POST, PUT, DELETE...)
34 */
35 public Http1Client(URL url, String requestMethod) {
36 super(url, requestMethod);
37 }
38
39 @Override
40 protected void setupConnection(ProgressMonitor progressMonitor) throws IOException {
41 connection = (HttpURLConnection) getURL().openConnection();
42 connection.setRequestMethod(getRequestMethod());
43 connection.setRequestProperty("User-Agent", Version.getInstance().getFullAgentString());
44 connection.setConnectTimeout(getConnectTimeout());
45 connection.setReadTimeout(getReadTimeout());
46 connection.setInstanceFollowRedirects(false); // we do that ourselves
47 if (getIfModifiedSince() > 0) {
48 connection.setIfModifiedSince(getIfModifiedSince());
49 }
50 connection.setUseCaches(isUseCache());
51 if (!isUseCache()) {
52 connection.setRequestProperty("Cache-Control", "no-cache");
53 }
54 for (Map.Entry<String, String> header : getHeaders().entrySet()) {
55 if (header.getValue() != null) {
56 connection.setRequestProperty(header.getKey(), header.getValue());
57 }
58 }
59
60 notifyConnect(progressMonitor);
61
62 if (requiresBody()) {
63 logRequestBody();
64 byte[] body = getRequestBody();
65 connection.setFixedLengthStreamingMode(body.length);
66 connection.setDoOutput(true);
67 try (OutputStream out = new BufferedOutputStream(
68 new ProgressOutputStream(connection.getOutputStream(), body.length,
69 progressMonitor, getOutputMessage(), isFinishOnCloseOutput()))) {
70 out.write(body);
71 }
72 }
73 }
74
75 @Override
76 protected ConnectionResponse performConnection() throws IOException {
77 connection.connect();
78 return new ConnectionResponse() {
79 @Override
80 public String getResponseVersion() {
81 return "HTTP_1";
82 }
83
84 @Override
85 public int getResponseCode() throws IOException {
86 return connection.getResponseCode();
87 }
88
89 @Override
90 public String getHeaderField(String name) {
91 return connection.getHeaderField(name);
92 }
93
94 @Override
95 public long getContentLengthLong() {
96 return connection.getContentLengthLong();
97 }
98
99 @Override
100 public Map<String, List<String>> getHeaderFields() {
101 return connection.getHeaderFields();
102 }
103 };
104 }
105
106 @Override
107 protected void performDisconnection() throws IOException {
108 connection.disconnect();
109 }
110
111 @Override
112 protected Response buildResponse(ProgressMonitor progressMonitor) throws IOException {
113 return new Http1Response(connection, progressMonitor);
114 }
115
116 /**
117 * A wrapper for the HTTP 1.x response.
118 */
119 public static final class Http1Response extends Response {
120 private final HttpURLConnection connection;
121
122 private Http1Response(HttpURLConnection connection, ProgressMonitor progressMonitor) throws IOException {
123 super(progressMonitor, connection.getResponseCode(), connection.getResponseMessage());
124 this.connection = connection;
125 debugRedirect();
126 }
127
128 @Override
129 public URL getURL() {
130 return connection.getURL();
131 }
132
133 @Override
134 public String getRequestMethod() {
135 return connection.getRequestMethod();
136 }
137
138 @Override
139 public InputStream getInputStream() throws IOException {
140 InputStream in;
141 try {
142 in = connection.getInputStream();
143 } catch (IOException ioe) {
144 Logging.debug(ioe);
145 in = Optional.ofNullable(connection.getErrorStream()).orElseGet(() -> new ByteArrayInputStream(new byte[]{}));
146 }
147 return in;
148 }
149
150 @Override
151 public String getContentEncoding() {
152 return connection.getContentEncoding();
153 }
154
155 @Override
156 public String getContentType() {
157 return connection.getHeaderField("Content-Type");
158 }
159
160 @Override
161 public long getExpiration() {
162 return connection.getExpiration();
163 }
164
165 @Override
166 public long getLastModified() {
167 return connection.getLastModified();
168 }
169
170 @Override
171 public long getContentLength() {
172 return connection.getContentLengthLong();
173 }
174
175 @Override
176 public String getHeaderField(String name) {
177 return connection.getHeaderField(name);
178 }
179
180 @Override
181 public Map<String, List<String>> getHeaderFields() {
182 // returned map from HttpUrlConnection is case sensitive, use case insensitive TreeMap to conform to RFC 2616
183 Map<String, List<String>> ret = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
184 for (Entry<String, List<String>> e: connection.getHeaderFields().entrySet()) {
185 if (e.getKey() != null) {
186 ret.put(e.getKey(), e.getValue());
187 }
188 }
189 return Collections.unmodifiableMap(ret);
190 }
191
192 @Override
193 public void disconnect() {
194 Http1Client.disconnect(connection);
195 }
196 }
197
198 /**
199 * @see HttpURLConnection#disconnect()
200 */
201 @Override
202 public void disconnect() {
203 Http1Client.disconnect(connection);
204 }
205
206 private static void disconnect(final HttpURLConnection connection) {
207 if (connection != null) {
208 // Fix upload aborts - see #263
209 connection.setConnectTimeout(100);
210 connection.setReadTimeout(100);
211 try {
212 Thread.sleep(100);
213 } catch (InterruptedException ex) {
214 Logging.warn("InterruptedException in " + Http1Client.class + " during cancel");
215 Thread.currentThread().interrupt();
216 }
217 connection.disconnect();
218 }
219 }
220}
Note: See TracBrowser for help on using the repository browser.