Changeset 9172 in josm for trunk/src/org/openstreetmap/josm/tools
- Timestamp:
- 2015-12-26T23:42:03+01:00 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/HttpClient.java
r9171 r9172 11 11 import java.net.HttpURLConnection; 12 12 import java.net.URL; 13 import java.util.List; 13 14 import java.util.Map; 14 15 import java.util.Scanner; 15 import java.util.concurrent.ConcurrentHashMap; 16 import java.util.TreeMap; 17 import java.util.regex.Matcher; 18 import java.util.regex.Pattern; 16 19 import java.util.zip.GZIPInputStream; 17 20 … … 30 33 private int connectTimeout = Main.pref.getInteger("socket.timeout.connect", 15) * 1000; 31 34 private int readTimeout = Main.pref.getInteger("socket.timeout.read", 30) * 1000; 32 private String accept;33 private String contentType;34 private String acceptEncoding = "gzip";35 private long contentLength;36 35 private byte[] requestBody; 37 36 private long ifModifiedSince; 38 private final Map<String, String> headers = new ConcurrentHashMap<>();37 private final Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 39 38 private int maxRedirects = Main.pref.getInteger("socket.maxredirects", 5); 40 39 private boolean useCache; 41 private boolean keepAlive;40 private String reasonForRequest; 42 41 43 42 private HttpClient(URL url, String requestMethod) { 44 43 this.url = url; 45 44 this.requestMethod = requestMethod; 45 this.headers.put("Accept-Encoding", "gzip"); 46 46 } 47 47 48 48 public Response connect() throws IOException { 49 49 final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 50 connection.setRequestMethod(requestMethod); 50 51 connection.setRequestProperty("User-Agent", Version.getInstance().getFullAgentString()); 51 52 connection.setConnectTimeout(connectTimeout); 52 53 connection.setReadTimeout(readTimeout); 53 if (accept != null) { 54 connection.setRequestProperty("Accept", accept); 55 } 56 if (contentType != null) { 57 connection.setRequestProperty("Content-Type", contentType); 58 } 59 if (acceptEncoding != null) { 60 connection.setRequestProperty("Accept-Encoding", acceptEncoding); 61 } 62 if (contentLength > 0) { 63 connection.setRequestProperty("Content-Length", String.valueOf(contentLength)); 64 } 54 connection.setInstanceFollowRedirects(maxRedirects > 0); 55 if (ifModifiedSince > 0) { 56 connection.setIfModifiedSince(ifModifiedSince); 57 } 58 connection.setUseCaches(useCache); 59 if (!useCache) { 60 connection.setRequestProperty("Cache-Control", "no-cache"); 61 } 62 for (Map.Entry<String, String> header : headers.entrySet()) { 63 if (header.getValue() != null) { 64 connection.setRequestProperty(header.getKey(), header.getValue()); 65 } 66 } 67 65 68 if ("PUT".equals(requestMethod) || "POST".equals(requestMethod) || "DELETE".equals(requestMethod)) { 69 headers.put("Content-Length", String.valueOf(requestBody.length)); 66 70 connection.setDoOutput(true); 67 71 try (OutputStream out = new BufferedOutputStream(connection.getOutputStream())) { 68 72 out.write(requestBody); 69 73 } 70 }71 if (ifModifiedSince > 0) {72 connection.setIfModifiedSince(ifModifiedSince);73 }74 connection.setUseCaches(useCache);75 if (!useCache) {76 connection.setRequestProperty("Cache-Control", "no-cache");77 }78 if (!keepAlive) {79 connection.setRequestProperty("Connection", "close");80 }81 for (Map.Entry<String, String> header : headers.entrySet()) {82 connection.setRequestProperty(header.getKey(), header.getValue());83 74 } 84 75 … … 87 78 try { 88 79 connection.connect(); 89 Main.info("{0} {1} => {2}", requestMethod, url, connection.getResponseCode()); 80 if (reasonForRequest != null && "".equalsIgnoreCase(reasonForRequest)) { 81 Main.info("{0} {1} ({2}) -> {3}", requestMethod, url, reasonForRequest, connection.getResponseCode()); 82 } else { 83 Main.info("{0} {1} -> {2}", requestMethod, url, connection.getResponseCode()); 84 } 85 if (Main.isDebugEnabled()) { 86 Main.debug("RESPONSE: " + connection.getHeaderFields()); 87 } 90 88 } catch (IOException e) { 91 89 //noinspection ThrowableResultOfMethodCallIgnored … … 105 103 Main.info(tr("Download redirected to ''{0}''", redirectLocation)); 106 104 return connect(); 107 } else { 105 } else if (maxRedirects == 0) { 108 106 String msg = tr("Too many redirects to the download URL detected. Aborting."); 109 107 throw new IOException(msg); … … 126 124 private final HttpURLConnection connection; 127 125 private final int responseCode; 126 private final String responseMessage; 128 127 private boolean uncompress; 128 private boolean uncompressAccordingToContentDisposition; 129 129 130 130 private Response(HttpURLConnection connection) throws IOException { 131 CheckParameterUtil.ensureParameterNotNull(connection, "connection"); 131 132 this.connection = connection; 132 133 this.responseCode = connection.getResponseCode(); 134 this.responseMessage = connection.getResponseMessage(); 133 135 } 134 136 … … 144 146 } 145 147 148 public Response uncompressAccordingToContentDisposition(boolean uncompressAccordingToContentDisposition) { 149 this.uncompressAccordingToContentDisposition = uncompressAccordingToContentDisposition; 150 return this; 151 } 152 153 /** 154 * @see HttpURLConnection#getURL() 155 */ 156 public URL getURL() { 157 return connection.getURL(); 158 } 159 160 /** 161 * @see HttpURLConnection#getRequestMethod() 162 */ 163 public String getRequestMethod() { 164 return connection.getRequestMethod(); 165 } 166 146 167 /** 147 168 * Returns an input stream that reads from this HTTP connection, or, 148 169 * error stream if the connection failed but the server sent useful data. 170 * 171 * Note: the return value can be null, if both the input and the error stream are null. 172 * Seems to be the case if the OSM server replies a 401 Unauthorized, see #3887 149 173 * 150 174 * @see HttpURLConnection#getInputStream() … … 160 184 in = "gzip".equalsIgnoreCase(getContentEncoding()) ? new GZIPInputStream(in) : in; 161 185 if (uncompress) { 162 return Compression.forContentType(getContentType()).getUncompressedInputStream(in); 163 } else { 164 return in; 165 } 186 final String contentType = getContentType(); 187 Main.debug("Uncompressing input stream according to Content-Type header: {0}", contentType); 188 in = Compression.forContentType(contentType).getUncompressedInputStream(in); 189 } 190 if (uncompressAccordingToContentDisposition) { 191 final String contentDisposition = getHeaderField("Content-Disposition"); 192 final Matcher matcher = Pattern.compile("filename=\"([^\"]+)\"").matcher(contentDisposition); 193 if (matcher.find()) { 194 Main.debug("Uncompressing input stream according to Content-Disposition header: {0}", contentDisposition); 195 in = Compression.byExtension(matcher.group(1)).getUncompressedInputStream(in); 196 } 197 } 198 return in; 166 199 } 167 200 … … 183 216 */ 184 217 public String fetchContent() throws IOException { 185 try (Scanner scanner = new Scanner(getContentReader())) { 186 return scanner. useDelimiter("\\A").next();218 try (Scanner scanner = new Scanner(getContentReader()).useDelimiter("\\A")) { 219 return scanner.hasNext() ? scanner.next() : ""; 187 220 } 188 221 } … … 198 231 199 232 /** 233 * Gets the response message from this HTTP connection. 234 * 235 * @see HttpURLConnection#getResponseMessage() 236 */ 237 public String getResponseMessage() { 238 return responseMessage; 239 } 240 241 /** 200 242 * Returns the {@code Content-Encoding} header. 201 243 */ … … 219 261 220 262 /** 263 * @see HttpURLConnection#getHeaderField(String) 264 */ 265 public String getHeaderField(String name) { 266 return connection.getHeaderField(name); 267 } 268 269 /** 270 * @see HttpURLConnection#getHeaderFields() 271 */ 272 public List<String> getHeaderFields(String name) { 273 return connection.getHeaderFields().get(name); 274 } 275 276 /** 221 277 * @see HttpURLConnection#disconnect() 222 278 */ 223 279 public void disconnect() { 280 // TODO is this block necessary for disconnecting? 281 // Fix upload aborts - see #263 282 connection.setConnectTimeout(100); 283 connection.setReadTimeout(100); 284 try { 285 Thread.sleep(100); 286 } catch (InterruptedException ex) { 287 Main.warn("InterruptedException in " + getClass().getSimpleName() + " during cancel"); 288 } 289 224 290 connection.disconnect(); 225 291 } … … 239 305 * Creates a new instance for the given URL and a {@code GET} request 240 306 * 241 * @param url the URL307 * @param url the URL 242 308 * @param requestMethod the HTTP request method to perform when calling 243 309 * @return a new instance … … 245 311 public static HttpClient create(URL url, String requestMethod) { 246 312 return new HttpClient(url, requestMethod); 313 } 314 315 /** 316 * Returns the URL set for this connection. 317 * @see #create(URL) 318 * @see #create(URL, String) 319 */ 320 public URL getURL() { 321 return url; 322 } 323 324 /** 325 * Returns the request method set for this connection. 326 * @see #create(URL, String) 327 */ 328 public String getRequestMethod() { 329 return requestMethod; 330 } 331 332 /** 333 * Returns the set value for the given {@code header}. 334 */ 335 public String getRequestHeader(String header) { 336 return headers.get(header); 247 337 } 248 338 … … 268 358 */ 269 359 public HttpClient keepAlive(boolean keepAlive) { 270 this.keepAlive = keepAlive; 271 return this; 360 return setHeader("Connection", keepAlive ? null : "close"); 272 361 } 273 362 … … 297 386 */ 298 387 public HttpClient setAccept(String accept) { 299 this.accept = accept; 300 return this; 301 } 302 303 /** 304 * Sets the {@code Content-Type} header. 305 * 306 * @return {@code this} 307 */ 308 public HttpClient setContentType(String contentType) { 309 this.contentType = contentType; 310 return this; 311 } 312 313 /** 314 * Sets the {@code Accept-Encoding} header. 315 * 316 * @return {@code this} 317 */ 318 public HttpClient setAcceptEncoding(String acceptEncoding) { 319 this.acceptEncoding = acceptEncoding; 320 return this; 321 } 322 323 /** 324 * Sets the {@code Content-Length} header for {@code PUT}/{@code POST} requests. 325 * 326 * @return {@code this} 327 */ 328 public HttpClient setContentLength(long contentLength) { 329 this.contentLength = contentLength; 330 return this; 388 return setHeader("Accept", accept); 331 389 } 332 390 … … 354 412 * Sets the maximum number of redirections to follow. 355 413 * 414 * Set {@code maxRedirects} to {@code -1} in order to ignore redirects, i.e., 415 * to not throw an {@link IOException} in {@link #connect()}. 416 * 356 417 * @return {@code this} 357 418 */ … … 378 439 public HttpClient setHeaders(Map<String, String> headers) { 379 440 this.headers.putAll(headers); 441 return this; 442 } 443 444 /** 445 * Sets a reason to show on console. Can be {@code null} if no reason is given. 446 */ 447 public HttpClient setReasonForRequest(String reasonForRequest) { 448 this.reasonForRequest = reasonForRequest; 380 449 return this; 381 450 }
Note:
See TracChangeset
for help on using the changeset viewer.
