Changeset 15229 in josm for trunk/src/org
- Timestamp:
- 2019-07-07T23:06:26+02:00 (5 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/MainApplication.java
r15222 r15229 150 150 import org.openstreetmap.josm.tools.FontsManager; 151 151 import org.openstreetmap.josm.tools.GBC; 152 import org.openstreetmap.josm.tools.Http1Client; 153 import org.openstreetmap.josm.tools.HttpClient; 152 154 import org.openstreetmap.josm.tools.I18n; 153 155 import org.openstreetmap.josm.tools.ImageProvider; … … 1042 1044 1043 1045 static void setupCallbacks() { 1046 HttpClient.setFactory(Http1Client::new); 1044 1047 OsmConnection.setOAuthAccessTokenFetcher(OAuthAuthorizationWizard::obtainAccessToken); 1045 1048 AbstractCredentialsAgent.setCredentialsProvider(CredentialDialog::promptCredentials); -
trunk/src/org/openstreetmap/josm/tools/HttpClient.java
r14522 r15229 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.io.BufferedOutputStream;7 6 import java.io.BufferedReader; 8 import java.io.ByteArrayInputStream;9 7 import java.io.IOException; 10 8 import java.io.InputStream; 11 import java.io.OutputStream;12 9 import java.net.CookieHandler; 13 10 import java.net.CookieManager; … … 16 13 import java.net.URL; 17 14 import java.nio.charset.StandardCharsets; 18 import java.util.Collections;19 15 import java.util.List; 20 16 import java.util.Locale; 21 17 import java.util.Map; 22 import java.util.Map.Entry; 23 import java.util.NoSuchElementException; 24 import java.util.Optional; 18 import java.util.Objects; 25 19 import java.util.Scanner; 26 20 import java.util.TreeMap; … … 30 24 import java.util.zip.GZIPInputStream; 31 25 32 import org.openstreetmap.josm.data.Version;33 26 import org.openstreetmap.josm.data.validation.routines.DomainValidator; 34 27 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; … … 37 30 import org.openstreetmap.josm.io.NetworkManager; 38 31 import org.openstreetmap.josm.io.ProgressInputStream; 39 import org.openstreetmap.josm.io.ProgressOutputStream;40 32 import org.openstreetmap.josm.io.UTFInputStreamReader; 41 33 import org.openstreetmap.josm.io.auth.DefaultAuthenticator; … … 46 38 * @since 9168 47 39 */ 48 public final class HttpClient { 40 public abstract class HttpClient { 41 42 /** 43 * HTTP client factory. 44 * @since 15229 45 */ 46 @FunctionalInterface 47 public interface HttpClientFactory { 48 /** 49 * Creates a new instance for the given URL and a {@code GET} request 50 * 51 * @param url the URL 52 * @param requestMethod the HTTP request method to perform when calling 53 * @return a new instance 54 */ 55 HttpClient create(URL url, String requestMethod); 56 } 49 57 50 58 private URL url; … … 59 67 private String reasonForRequest; 60 68 private String outputMessage = tr("Uploading data ..."); 61 private HttpURLConnection connection; // to allow disconnecting before `response` is set62 69 private Response response; 63 70 private boolean finishOnCloseOutput = true; … … 71 78 Pattern.CASE_INSENSITIVE); 72 79 80 private static HttpClientFactory factory; 81 73 82 static { 74 83 try { … … 79 88 } 80 89 81 private HttpClient(URL url, String requestMethod) { 90 /** 91 * Registers a new HTTP client factory. 92 * @param newFactory new HTTP client factory 93 * @since 15229 94 */ 95 public static void setFactory(HttpClientFactory newFactory) { 96 factory = Objects.requireNonNull(newFactory); 97 } 98 99 /** 100 * Constructs a new {@code HttpClient}. 101 * @param url URL to access 102 * @param requestMethod HTTP request method (GET, POST, PUT, DELETE...) 103 */ 104 protected HttpClient(URL url, String requestMethod) { 82 105 try { 83 106 String host = url.getHost(); … … 96 119 * @throws IOException if any I/O error occurs 97 120 */ 98 public Response connect() throws IOException {121 public final Response connect() throws IOException { 99 122 return connect(null); 100 123 } … … 107 130 * @since 9179 108 131 */ 109 public Response connect(ProgressMonitor progressMonitor) throws IOException {132 public final Response connect(ProgressMonitor progressMonitor) throws IOException { 110 133 if (progressMonitor == null) { 111 134 progressMonitor = NullProgressMonitor.INSTANCE; 112 135 } 113 final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 114 this.connection = connection; 115 connection.setRequestMethod(requestMethod); 116 connection.setRequestProperty("User-Agent", Version.getInstance().getFullAgentString()); 117 connection.setConnectTimeout(connectTimeout); 118 connection.setReadTimeout(readTimeout); 119 connection.setInstanceFollowRedirects(false); // we do that ourselves 120 if (ifModifiedSince > 0) { 121 connection.setIfModifiedSince(ifModifiedSince); 122 } 123 connection.setUseCaches(useCache); 124 if (!useCache) { 125 connection.setRequestProperty("Cache-Control", "no-cache"); 126 } 127 for (Map.Entry<String, String> header : headers.entrySet()) { 128 if (header.getValue() != null) { 129 connection.setRequestProperty(header.getKey(), header.getValue()); 130 } 131 } 132 133 progressMonitor.beginTask(tr("Contacting Server..."), 1); 134 progressMonitor.indeterminateSubTask(null); 135 136 if ("PUT".equals(requestMethod) || "POST".equals(requestMethod) || "DELETE".equals(requestMethod)) { 137 Logging.info("{0} {1} ({2}) ...", requestMethod, url, Utils.getSizeString(requestBody.length, Locale.getDefault())); 138 if (Logging.isTraceEnabled() && requestBody.length > 0) { 139 Logging.trace("BODY: {0}", new String(requestBody, StandardCharsets.UTF_8)); 140 } 141 connection.setFixedLengthStreamingMode(requestBody.length); 142 connection.setDoOutput(true); 143 try (OutputStream out = new BufferedOutputStream( 144 new ProgressOutputStream(connection.getOutputStream(), requestBody.length, 145 progressMonitor, outputMessage, finishOnCloseOutput))) { 146 out.write(requestBody); 147 } 148 } 136 setupConnection(progressMonitor); 149 137 150 138 boolean successfulConnection = false; 151 139 try { 140 ConnectionResponse cr; 152 141 try { 153 c onnection.connect();142 cr = performConnection(); 154 143 final boolean hasReason = reasonForRequest != null && !reasonForRequest.isEmpty(); 155 Logging.info("{0} {1}{2} -> {3} {4}",156 requestMethod, url, hasReason ? (" (" + reasonForRequest + ')') : "",157 c onnection.getResponseCode(),158 c onnection.getContentLengthLong() > 0159 ? (" (" + Utils.getSizeString(c onnection.getContentLengthLong(), Locale.getDefault()) + ')')144 Logging.info("{0} {1}{2} -> {3} {4}{5}", 145 getRequestMethod(), getURL(), hasReason ? (" (" + reasonForRequest + ')') : "", 146 cr.getResponseVersion(), cr.getResponseCode(), 147 cr.getContentLengthLong() > 0 148 ? (" (" + Utils.getSizeString(cr.getContentLengthLong(), Locale.getDefault()) + ')') 160 149 : "" 161 150 ); 162 151 if (Logging.isDebugEnabled()) { 163 152 try { 164 Logging.debug("RESPONSE: {0}", c onnection.getHeaderFields());153 Logging.debug("RESPONSE: {0}", cr.getHeaderFields()); 165 154 } catch (IllegalArgumentException e) { 166 155 Logging.warn(e); 167 156 } 168 157 } 169 if (DefaultAuthenticator.getInstance().isEnabled() && c onnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {158 if (DefaultAuthenticator.getInstance().isEnabled() && cr.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) { 170 159 DefaultAuthenticator.getInstance().addFailedCredentialHost(url.getHost()); 171 160 } 172 } catch (IOException | IllegalArgumentException | NoSuchElementException e) {161 } catch (IOException | RuntimeException e) { 173 162 Logging.info("{0} {1} -> !!!", requestMethod, url); 174 163 Logging.warn(e); … … 177 166 throw e; 178 167 } 179 if (isRedirect(c onnection.getResponseCode())) {180 final String redirectLocation = c onnection.getHeaderField("Location");168 if (isRedirect(cr.getResponseCode())) { 169 final String redirectLocation = cr.getHeaderField("Location"); 181 170 if (redirectLocation == null) { 182 171 /* I18n: argument is HTTP response code */ 183 172 throw new IOException(tr("Unexpected response from HTTP server. Got {0} response without ''Location'' header." + 184 " Can''t redirect. Aborting.", c onnection.getResponseCode()));173 " Can''t redirect. Aborting.", cr.getResponseCode())); 185 174 } else if (maxRedirects > 0) { 186 175 url = new URL(url, redirectLocation); … … 193 182 } 194 183 } 195 response = new Response(connection,progressMonitor);184 response = buildResponse(progressMonitor); 196 185 successfulConnection = true; 197 186 return response; 198 187 } finally { 199 188 if (!successfulConnection) { 200 connection.disconnect();189 performDisconnection(); 201 190 } 191 } 192 } 193 194 protected abstract void setupConnection(ProgressMonitor progressMonitor) throws IOException; 195 196 protected abstract ConnectionResponse performConnection() throws IOException; 197 198 protected abstract void performDisconnection() throws IOException; 199 200 protected abstract Response buildResponse(ProgressMonitor progressMonitor) throws IOException; 201 202 protected final void notifyConnect(ProgressMonitor progressMonitor) { 203 progressMonitor.beginTask(tr("Contacting Server..."), 1); 204 progressMonitor.indeterminateSubTask(null); 205 } 206 207 protected final void logRequestBody() { 208 Logging.info("{0} {1} ({2}) ...", requestMethod, url, Utils.getSizeString(requestBody.length, Locale.getDefault())); 209 if (Logging.isTraceEnabled() && hasRequestBody()) { 210 Logging.trace("BODY: {0}", new String(requestBody, StandardCharsets.UTF_8)); 202 211 } 203 212 } … … 210 219 * @since 9309 211 220 */ 212 public Response getResponse() {221 public final Response getResponse() { 213 222 return response; 214 223 } 215 224 216 225 /** 226 * A wrapper for the HTTP connection response. 227 * @since 15229 228 */ 229 public interface ConnectionResponse { 230 /** 231 * Gets the HTTP version from the HTTP response. 232 * @return the HTTP version from the HTTP response 233 */ 234 String getResponseVersion(); 235 236 /** 237 * Gets the status code from an HTTP response message. 238 * For example, in the case of the following status lines: 239 * <PRE> 240 * HTTP/1.0 200 OK 241 * HTTP/1.0 401 Unauthorized 242 * </PRE> 243 * It will return 200 and 401 respectively. 244 * Returns -1 if no code can be discerned 245 * from the response (i.e., the response is not valid HTTP). 246 * @return the HTTP Status-Code, or -1 247 * @throws IOException if an error occurred connecting to the server. 248 */ 249 int getResponseCode() throws IOException; 250 251 /** 252 * Returns the value of the {@code content-length} header field as a long. 253 * 254 * @return the content length of the resource that this connection's URL 255 * references, or {@code -1} if the content length is not known. 256 */ 257 long getContentLengthLong(); 258 259 /** 260 * Returns an unmodifiable Map of the header fields. 261 * The Map keys are Strings that represent the response-header field names. 262 * Each Map value is an unmodifiable List of Strings that represents 263 * the corresponding field values. 264 * 265 * @return a Map of header fields 266 */ 267 Map<String, List<String>> getHeaderFields(); 268 269 /** 270 * Returns the value of the named header field. 271 * @param name the name of a header field. 272 * @return the value of the named header field, or {@code null} 273 * if there is no such field in the header. 274 */ 275 String getHeaderField(String name); 276 } 277 278 /** 217 279 * A wrapper for the HTTP response. 218 280 */ 219 public static final class Response { 220 private final HttpURLConnection connection; 281 public abstract static class Response { 221 282 private final ProgressMonitor monitor; 222 283 private final int responseCode; … … 226 287 private String responseData; 227 288 228 pr ivate Response(HttpURLConnection connection, ProgressMonitor monitor) throws IOException{229 CheckParameterUtil.ensureParameterNotNull(connection, "connection");230 CheckParameterUtil.ensureParameterNotNull(monitor, "monitor");231 this. connection = connection;232 this.monitor = monitor;233 this.responseCode = connection.getResponseCode(); 234 this.responseMessage = connection.getResponseMessage();235 if ( this.responseCode >= 300) {289 protected Response(ProgressMonitor monitor, int responseCode, String responseMessage) { 290 this.monitor = Objects.requireNonNull(monitor, "monitor"); 291 this.responseCode = responseCode; 292 this.responseMessage = responseMessage; 293 } 294 295 protected final void debugRedirect() throws IOException { 296 if (responseCode >= 300) { 236 297 String contentType = getContentType(); 237 if (contentType == null || ( 238 contentType.contains("text") || 239 contentType.contains("html") || 240 contentType.contains("xml")) 241 ) { 242 String content = this.fetchContent(); 243 if (content.isEmpty()) { 244 Logging.debug("Server did not return any body"); 245 } else { 246 Logging.debug("Response body: "); 247 Logging.debug(this.fetchContent()); 248 } 298 if (contentType == null || 299 contentType.contains("text") || 300 contentType.contains("html") || 301 contentType.contains("xml") 302 ) { 303 String content = fetchContent(); 304 Logging.debug(content.isEmpty() ? "Server did not return any body" : "Response body: \n" + content); 249 305 } else { 250 Logging.debug("Server returned content: {0} of length: {1}. Not printing.", contentType, this.getContentLength());306 Logging.debug("Server returned content: {0} of length: {1}. Not printing.", contentType, getContentLength()); 251 307 } 252 308 } … … 259 315 * @return {@code this} 260 316 */ 261 public Response uncompress(boolean uncompress) {317 public final Response uncompress(boolean uncompress) { 262 318 this.uncompress = uncompress; 263 319 return this; … … 272 328 * @since 9172 273 329 */ 274 public Response uncompressAccordingToContentDisposition(boolean uncompressAccordingToContentDisposition) {330 public final Response uncompressAccordingToContentDisposition(boolean uncompressAccordingToContentDisposition) { 275 331 this.uncompressAccordingToContentDisposition = uncompressAccordingToContentDisposition; 276 332 return this; … … 283 339 * @since 9172 284 340 */ 285 public URL getURL() { 286 return connection.getURL(); 287 } 341 public abstract URL getURL(); 288 342 289 343 /** … … 293 347 * @since 9172 294 348 */ 295 public String getRequestMethod() { 296 return connection.getRequestMethod(); 297 } 349 public abstract String getRequestMethod(); 298 350 299 351 /** … … 310 362 */ 311 363 @SuppressWarnings("resource") 312 public InputStream getContent() throws IOException { 313 InputStream in; 314 try { 315 in = connection.getInputStream(); 316 } catch (IOException ioe) { 317 Logging.debug(ioe); 318 in = Optional.ofNullable(connection.getErrorStream()).orElseGet(() -> new ByteArrayInputStream(new byte[]{})); 319 } 364 public final InputStream getContent() throws IOException { 365 InputStream in = getInputStream(); 320 366 in = new ProgressInputStream(in, getContentLength(), monitor); 321 367 in = "gzip".equalsIgnoreCase(getContentEncoding()) ? new GZIPInputStream(in) : in; … … 339 385 } 340 386 387 protected abstract InputStream getInputStream() throws IOException; 388 341 389 /** 342 390 * Returns {@link #getContent()} wrapped in a buffered reader. … … 346 394 * @throws IOException if any I/O error occurs 347 395 */ 348 public BufferedReader getContentReader() throws IOException {396 public final BufferedReader getContentReader() throws IOException { 349 397 return new BufferedReader( 350 398 UTFInputStreamReader.create(getContent()) … … 357 405 * @throws IOException if any I/O error occurs 358 406 */ 359 public synchronized String fetchContent() throws IOException {407 public final synchronized String fetchContent() throws IOException { 360 408 if (responseData == null) { 361 409 try (Scanner scanner = new Scanner(getContentReader()).useDelimiter("\\A")) { // \A - beginning of input … … 372 420 * @see HttpURLConnection#getResponseCode() 373 421 */ 374 public int getResponseCode() {422 public final int getResponseCode() { 375 423 return responseCode; 376 424 } … … 383 431 * @since 9172 384 432 */ 385 public String getResponseMessage() {433 public final String getResponseMessage() { 386 434 return responseMessage; 387 435 } … … 392 440 * @see HttpURLConnection#getContentEncoding() 393 441 */ 394 public String getContentEncoding() { 395 return connection.getContentEncoding(); 396 } 442 public abstract String getContentEncoding(); 397 443 398 444 /** 399 445 * Returns the {@code Content-Type} header. 400 446 * @return {@code Content-Type} HTTP header 401 */ 402 public String getContentType() { 403 return connection.getHeaderField("Content-Type"); 404 } 447 * @see HttpURLConnection#getContentType() 448 */ 449 public abstract String getContentType(); 405 450 406 451 /** … … 410 455 * @since 9232 411 456 */ 412 public long getExpiration() { 413 return connection.getExpiration(); 414 } 457 public abstract long getExpiration(); 415 458 416 459 /** … … 420 463 * @since 9232 421 464 */ 422 public long getLastModified() { 423 return connection.getLastModified(); 424 } 465 public abstract long getLastModified(); 425 466 426 467 /** … … 429 470 * @see HttpURLConnection#getContentLengthLong() 430 471 */ 431 public long getContentLength() { 432 return connection.getContentLengthLong(); 433 } 472 public abstract long getContentLength(); 434 473 435 474 /** … … 440 479 * @since 9172 441 480 */ 442 public String getHeaderField(String name) { 443 return connection.getHeaderField(name); 444 } 481 public abstract String getHeaderField(String name); 445 482 446 483 /** … … 451 488 * @since 9232 452 489 */ 453 public Map<String, List<String>> getHeaderFields() { 454 // returned map from HttpUrlConnection is case sensitive, use case insensitive TreeMap to conform to RFC 2616 455 Map<String, List<String>> ret = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 456 for (Entry<String, List<String>> e: connection.getHeaderFields().entrySet()) { 457 if (e.getKey() != null) { 458 ret.put(e.getKey(), e.getValue()); 459 } 460 } 461 return Collections.unmodifiableMap(ret); 462 } 490 public abstract Map<String, List<String>> getHeaderFields(); 463 491 464 492 /** 465 493 * @see HttpURLConnection#disconnect() 466 494 */ 467 public void disconnect() { 468 HttpClient.disconnect(connection); 469 } 495 public abstract void disconnect(); 470 496 } 471 497 … … 488 514 */ 489 515 public static HttpClient create(URL url, String requestMethod) { 490 return new HttpClient(url, requestMethod);516 return factory.create(url, requestMethod); 491 517 } 492 518 … … 498 524 * @since 9172 499 525 */ 500 public URL getURL() {526 public final URL getURL() { 501 527 return url; 528 } 529 530 /** 531 * Returns the request body set for this connection. 532 * @return the HTTP request body, or null 533 * @since 15229 534 */ 535 public final byte[] getRequestBody() { 536 return requestBody; 537 } 538 539 /** 540 * Determines if a non-empty request body has been set for this connection. 541 * @return {@code true} if the request body is set and non-empty 542 * @since 15229 543 */ 544 public final boolean hasRequestBody() { 545 return requestBody != null && requestBody.length > 0; 546 } 547 548 /** 549 * Determines if the underlying HTTP method requires a body. 550 * @return {@code true} if the underlying HTTP method requires a body 551 * @since 15229 552 */ 553 public final boolean requiresBody() { 554 return "PUT".equals(requestMethod) || "POST".equals(requestMethod) || "DELETE".equals(requestMethod); 502 555 } 503 556 … … 508 561 * @since 9172 509 562 */ 510 public String getRequestMethod() {563 public final String getRequestMethod() { 511 564 return requestMethod; 512 565 } … … 518 571 * @since 9172 519 572 */ 520 public String getRequestHeader(String header) {573 public final String getRequestHeader(String header) { 521 574 return headers.get(header); 522 575 } 523 576 524 577 /** 578 * Returns the connect timeout. 579 * @return the connect timeout, in milliseconds 580 * @since 15229 581 */ 582 public final int getConnectTimeout() { 583 return connectTimeout; 584 } 585 586 /** 587 * Returns the read timeout. 588 * @return the read timeout, in milliseconds 589 * @since 15229 590 */ 591 public final int getReadTimeout() { 592 return readTimeout; 593 } 594 595 /** 596 * Returns the {@code If-Modified-Since} header value. 597 * @return the {@code If-Modified-Since} header value 598 * @since 15229 599 */ 600 public final long getIfModifiedSince() { 601 return ifModifiedSince; 602 } 603 604 /** 605 * Determines whether not to set header {@code Cache-Control=no-cache} 606 * @return whether not to set header {@code Cache-Control=no-cache} 607 * @since 15229 608 */ 609 public final boolean isUseCache() { 610 return useCache; 611 } 612 613 /** 614 * Returns the headers. 615 * @return the headers 616 * @since 15229 617 */ 618 public final Map<String, String> getHeaders() { 619 return headers; 620 } 621 622 /** 623 * Returns the reason for request. 624 * @return the reason for request 625 * @since 15229 626 */ 627 public final String getReasonForRequest() { 628 return reasonForRequest; 629 } 630 631 /** 632 * Returns the output message. 633 * @return the output message 634 */ 635 protected final String getOutputMessage() { 636 return outputMessage; 637 } 638 639 /** 640 * Determines whether the progress monitor task will be finished when the output stream is closed. {@code true} by default. 641 * @return the finishOnCloseOutput 642 */ 643 protected final boolean isFinishOnCloseOutput() { 644 return finishOnCloseOutput; 645 } 646 647 /** 525 648 * Sets whether not to set header {@code Cache-Control=no-cache} 526 649 * … … 529 652 * @see HttpURLConnection#setUseCaches(boolean) 530 653 */ 531 public HttpClient useCache(boolean useCache) {654 public final HttpClient useCache(boolean useCache) { 532 655 this.useCache = useCache; 533 656 return this; … … 543 666 * @return {@code this} 544 667 */ 545 public HttpClient keepAlive(boolean keepAlive) {668 public final HttpClient keepAlive(boolean keepAlive) { 546 669 return setHeader("Connection", keepAlive ? null : "close"); 547 670 } … … 555 678 * @see HttpURLConnection#setConnectTimeout(int) 556 679 */ 557 public HttpClient setConnectTimeout(int connectTimeout) {680 public final HttpClient setConnectTimeout(int connectTimeout) { 558 681 this.connectTimeout = connectTimeout; 559 682 return this; … … 568 691 * @see HttpURLConnection#setReadTimeout(int) 569 692 */ 570 public HttpClient setReadTimeout(int readTimeout) {693 public final HttpClient setReadTimeout(int readTimeout) { 571 694 this.readTimeout = readTimeout; 572 695 return this; … … 579 702 * @return {@code this} 580 703 */ 581 public HttpClient setAccept(String accept) {704 public final HttpClient setAccept(String accept) { 582 705 return setHeader("Accept", accept); 583 706 } … … 589 712 * @return {@code this} 590 713 */ 591 public HttpClient setRequestBody(byte[] requestBody) {714 public final HttpClient setRequestBody(byte[] requestBody) { 592 715 this.requestBody = Utils.copyArray(requestBody); 593 716 return this; … … 600 723 * @return {@code this} 601 724 */ 602 public HttpClient setIfModifiedSince(long ifModifiedSince) {725 public final HttpClient setIfModifiedSince(long ifModifiedSince) { 603 726 this.ifModifiedSince = ifModifiedSince; 604 727 return this; … … 614 737 * @return {@code this} 615 738 */ 616 public HttpClient setMaxRedirects(int maxRedirects) {739 public final HttpClient setMaxRedirects(int maxRedirects) { 617 740 this.maxRedirects = maxRedirects; 618 741 return this; … … 626 749 * @return {@code this} 627 750 */ 628 public HttpClient setHeader(String key, String value) {751 public final HttpClient setHeader(String key, String value) { 629 752 this.headers.put(key, value); 630 753 return this; … … 637 760 * @return {@code this} 638 761 */ 639 public HttpClient setHeaders(Map<String, String> headers) {762 public final HttpClient setHeaders(Map<String, String> headers) { 640 763 this.headers.putAll(headers); 641 764 return this; … … 648 771 * @since 9172 649 772 */ 650 public HttpClient setReasonForRequest(String reasonForRequest) {773 public final HttpClient setReasonForRequest(String reasonForRequest) { 651 774 this.reasonForRequest = reasonForRequest; 652 775 return this; … … 660 783 * @since 12711 661 784 */ 662 public HttpClient setOutputMessage(String outputMessage) {785 public final HttpClient setOutputMessage(String outputMessage) { 663 786 this.outputMessage = outputMessage; 664 787 return this; … … 671 794 * @since 10302 672 795 */ 673 public HttpClient setFinishOnCloseOutput(boolean finishOnCloseOutput) {796 public final HttpClient setFinishOnCloseOutput(boolean finishOnCloseOutput) { 674 797 this.finishOnCloseOutput = finishOnCloseOutput; 675 798 return this; … … 690 813 691 814 /** 815 * Disconnect client. 692 816 * @see HttpURLConnection#disconnect() 693 817 * @since 9309 694 818 */ 695 public void disconnect() { 696 HttpClient.disconnect(connection); 697 } 698 699 private static void disconnect(final HttpURLConnection connection) { 700 if (connection != null) { 701 // Fix upload aborts - see #263 702 connection.setConnectTimeout(100); 703 connection.setReadTimeout(100); 704 try { 705 Thread.sleep(100); 706 } catch (InterruptedException ex) { 707 Logging.warn("InterruptedException in " + HttpClient.class + " during cancel"); 708 Thread.currentThread().interrupt(); 709 } 710 connection.disconnect(); 711 } 712 } 819 public abstract void disconnect(); 713 820 714 821 /**
Note:
See TracChangeset
for help on using the changeset viewer.