| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.net; | 5 package org.chromium.net; |
| 6 | 6 |
| 7 import android.util.Log; | 7 import android.util.Log; |
| 8 | 8 |
| 9 import org.apache.http.conn.ConnectTimeoutException; | 9 import org.apache.http.conn.ConnectTimeoutException; |
| 10 import org.chromium.base.CalledByNative; | 10 import org.chromium.base.CalledByNative; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 private final WritableByteChannel mSink; | 40 private final WritableByteChannel mSink; |
| 41 private Map<String, String> mAdditionalHeaders; | 41 private Map<String, String> mAdditionalHeaders; |
| 42 private String mUploadContentType; | 42 private String mUploadContentType; |
| 43 private String mMethod; | 43 private String mMethod; |
| 44 private byte[] mUploadData; | 44 private byte[] mUploadData; |
| 45 private ReadableByteChannel mUploadChannel; | 45 private ReadableByteChannel mUploadChannel; |
| 46 private boolean mChunkedUpload; | 46 private boolean mChunkedUpload; |
| 47 private IOException mSinkException; | 47 private IOException mSinkException; |
| 48 private volatile boolean mStarted; | 48 private volatile boolean mStarted; |
| 49 private volatile boolean mCanceled; | 49 private volatile boolean mCanceled; |
| 50 private volatile boolean mRecycled; | |
| 51 private volatile boolean mFinished; | 50 private volatile boolean mFinished; |
| 52 private boolean mHeadersAvailable; | 51 private boolean mHeadersAvailable; |
| 53 private String mContentType; | |
| 54 private long mUploadContentLength; | 52 private long mUploadContentLength; |
| 55 private final HttpUrlRequestListener mListener; | 53 private final HttpUrlRequestListener mListener; |
| 56 private boolean mBufferFullResponse; | 54 private boolean mBufferFullResponse; |
| 57 private long mOffset; | 55 private long mOffset; |
| 58 private long mContentLength; | |
| 59 private long mContentLengthLimit; | 56 private long mContentLengthLimit; |
| 60 private boolean mCancelIfContentLengthOverLimit; | 57 private boolean mCancelIfContentLengthOverLimit; |
| 61 private boolean mContentLengthOverLimit; | 58 private boolean mContentLengthOverLimit; |
| 62 private boolean mSkippingToOffset; | 59 private boolean mSkippingToOffset; |
| 63 private long mSize; | 60 private long mSize; |
| 61 |
| 64 // Indicates whether redirects have been disabled. | 62 // Indicates whether redirects have been disabled. |
| 65 private boolean mDisableRedirects; | 63 private boolean mDisableRedirects; |
| 64 |
| 65 // Http status code. Default to 0. Populated in onResponseStarted(). |
| 66 private int mHttpStatusCode = 0; |
| 67 |
| 68 // Http status text. Default to null. Populated in onResponseStarted(). |
| 69 private String mHttpStatusText; |
| 70 |
| 71 // Content type. Default to null. Populated in onResponseStarted(). |
| 72 private String mContentType; |
| 73 |
| 74 // Compressed content length as reported by the server. Populated in onRespo
nseStarted(). |
| 75 private long mContentLength; |
| 76 |
| 77 // Native error code. Default to no error. Populated in onRequestComplete(). |
| 78 private int mErrorCode = ChromiumUrlRequestError.SUCCESS; |
| 79 |
| 80 // Native error string. Default to null. Populated in onRequestComplete(). |
| 81 private String mErrorString; |
| 82 |
| 83 // Protects access of mUrlRequestAdapter, mStarted, mCanceled, and mFinished
. |
| 66 private final Object mLock = new Object(); | 84 private final Object mLock = new Object(); |
| 67 | 85 |
| 68 public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext, | 86 public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext, |
| 69 String url, int priority, Map<String, String> headers, | 87 String url, int priority, Map<String, String> headers, |
| 70 HttpUrlRequestListener listener) { | 88 HttpUrlRequestListener listener) { |
| 71 this(requestContext, url, priority, headers, | 89 this(requestContext, url, priority, headers, |
| 72 new ChunkedWritableByteChannel(), listener); | 90 new ChunkedWritableByteChannel(), listener); |
| 73 mBufferFullResponse = true; | 91 mBufferFullResponse = true; |
| 74 } | 92 } |
| 75 | 93 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 } | 143 } |
| 126 | 144 |
| 127 @Override | 145 @Override |
| 128 public void setContentLengthLimit(long limit, boolean cancelEarly) { | 146 public void setContentLengthLimit(long limit, boolean cancelEarly) { |
| 129 mContentLengthLimit = limit; | 147 mContentLengthLimit = limit; |
| 130 mCancelIfContentLengthOverLimit = cancelEarly; | 148 mCancelIfContentLengthOverLimit = cancelEarly; |
| 131 } | 149 } |
| 132 | 150 |
| 133 @Override | 151 @Override |
| 134 public int getHttpStatusCode() { | 152 public int getHttpStatusCode() { |
| 135 int httpStatusCode = nativeGetHttpStatusCode(mUrlRequestAdapter); | |
| 136 | |
| 137 // TODO(mef): Investigate the following: | 153 // TODO(mef): Investigate the following: |
| 138 // If we have been able to successfully resume a previously interrupted | 154 // If we have been able to successfully resume a previously interrupted |
| 139 // download, the status code will be 206, not 200. Since the rest of the | 155 // download, the status code will be 206, not 200. Since the rest of the |
| 140 // application is expecting 200 to indicate success, we need to fake it. | 156 // application is expecting 200 to indicate success, we need to fake it. |
| 141 if (httpStatusCode == 206) { | 157 if (mHttpStatusCode == 206) { |
| 142 httpStatusCode = 200; | 158 return 200; |
| 143 } | 159 } |
| 144 return httpStatusCode; | 160 return mHttpStatusCode; |
| 145 } | 161 } |
| 146 | 162 |
| 147 @Override | 163 @Override |
| 148 public String getHttpStatusText() { | 164 public String getHttpStatusText() { |
| 149 return nativeGetHttpStatusText(mUrlRequestAdapter); | 165 return mHttpStatusText; |
| 150 } | 166 } |
| 151 | 167 |
| 152 /** | 168 /** |
| 153 * Returns an exception if any, or null if the request was completed | 169 * Returns an exception if any, or null if the request has not completed or |
| 154 * successfully. | 170 * completed successfully. |
| 155 */ | 171 */ |
| 156 @Override | 172 @Override |
| 157 public IOException getException() { | 173 public IOException getException() { |
| 158 if (mSinkException != null) { | 174 if (mSinkException != null) { |
| 159 return mSinkException; | 175 return mSinkException; |
| 160 } | 176 } |
| 161 | 177 |
| 162 validateNotRecycled(); | 178 switch (mErrorCode) { |
| 163 | |
| 164 int errorCode = nativeGetErrorCode(mUrlRequestAdapter); | |
| 165 switch (errorCode) { | |
| 166 case ChromiumUrlRequestError.SUCCESS: | 179 case ChromiumUrlRequestError.SUCCESS: |
| 167 if (mContentLengthOverLimit) { | 180 if (mContentLengthOverLimit) { |
| 168 return new ResponseTooLargeException(); | 181 return new ResponseTooLargeException(); |
| 169 } | 182 } |
| 170 return null; | 183 return null; |
| 171 case ChromiumUrlRequestError.UNKNOWN: | 184 case ChromiumUrlRequestError.UNKNOWN: |
| 172 return new IOException( | 185 return new IOException(mErrorString); |
| 173 nativeGetErrorString(mUrlRequestAdapter)); | |
| 174 case ChromiumUrlRequestError.MALFORMED_URL: | 186 case ChromiumUrlRequestError.MALFORMED_URL: |
| 175 return new MalformedURLException("Malformed URL: " + mUrl); | 187 return new MalformedURLException("Malformed URL: " + mUrl); |
| 176 case ChromiumUrlRequestError.CONNECTION_TIMED_OUT: | 188 case ChromiumUrlRequestError.CONNECTION_TIMED_OUT: |
| 177 return new ConnectTimeoutException("Connection timed out"); | 189 return new ConnectTimeoutException("Connection timed out"); |
| 178 case ChromiumUrlRequestError.UNKNOWN_HOST: | 190 case ChromiumUrlRequestError.UNKNOWN_HOST: |
| 179 String host; | 191 String host; |
| 180 try { | 192 try { |
| 181 host = new URL(mUrl).getHost(); | 193 host = new URL(mUrl).getHost(); |
| 182 } catch (MalformedURLException e) { | 194 } catch (MalformedURLException e) { |
| 183 host = mUrl; | 195 host = mUrl; |
| 184 } | 196 } |
| 185 return new UnknownHostException("Unknown host: " + host); | 197 return new UnknownHostException("Unknown host: " + host); |
| 186 case ChromiumUrlRequestError.TOO_MANY_REDIRECTS: | 198 case ChromiumUrlRequestError.TOO_MANY_REDIRECTS: |
| 187 return new IOException("Request failed because there were too " | 199 return new IOException("Request failed because there were too " |
| 188 + "many redirects or redirects have been disabled"); | 200 + "many redirects or redirects have been disabled"); |
| 189 default: | 201 default: |
| 190 throw new IllegalStateException( | 202 throw new IllegalStateException( |
| 191 "Unrecognized error code: " + errorCode); | 203 "Unrecognized error code: " + mErrorCode); |
| 192 } | 204 } |
| 193 } | 205 } |
| 194 | 206 |
| 195 @Override | 207 @Override |
| 196 public ByteBuffer getByteBuffer() { | 208 public ByteBuffer getByteBuffer() { |
| 197 return ((ChunkedWritableByteChannel) getSink()).getByteBuffer(); | 209 return ((ChunkedWritableByteChannel) getSink()).getByteBuffer(); |
| 198 } | 210 } |
| 199 | 211 |
| 200 @Override | 212 @Override |
| 201 public byte[] getResponseAsBytes() { | 213 public byte[] getResponseAsBytes() { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 } | 322 } |
| 311 | 323 |
| 312 @Override | 324 @Override |
| 313 public void setHttpMethod(String method) { | 325 public void setHttpMethod(String method) { |
| 314 validateNotStarted(); | 326 validateNotStarted(); |
| 315 mMethod = method; | 327 mMethod = method; |
| 316 } | 328 } |
| 317 | 329 |
| 318 @Override | 330 @Override |
| 319 public void disableRedirects() { | 331 public void disableRedirects() { |
| 320 mDisableRedirects = true; | 332 synchronized (mLock) { |
| 321 validateNotStarted(); | 333 validateNotStarted(); |
| 322 nativeDisableRedirects(mUrlRequestAdapter); | 334 validateNativeAdapterNotDestroyed(); |
| 335 mDisableRedirects = true; |
| 336 nativeDisableRedirects(mUrlRequestAdapter); |
| 337 } |
| 323 } | 338 } |
| 324 | 339 |
| 325 public WritableByteChannel getSink() { | 340 public WritableByteChannel getSink() { |
| 326 return mSink; | 341 return mSink; |
| 327 } | 342 } |
| 328 | 343 |
| 329 @Override | 344 @Override |
| 330 public void start() { | 345 public void start() { |
| 331 synchronized (mLock) { | 346 synchronized (mLock) { |
| 332 if (mCanceled) { | 347 if (mCanceled) { |
| 333 return; | 348 return; |
| 334 } | 349 } |
| 335 | 350 |
| 336 validateNotStarted(); | 351 validateNotStarted(); |
| 337 validateNotRecycled(); | 352 validateNativeAdapterNotDestroyed(); |
| 338 | 353 |
| 339 mStarted = true; | 354 mStarted = true; |
| 340 | 355 |
| 341 if (mHeaders != null && !mHeaders.isEmpty()) { | 356 if (mHeaders != null && !mHeaders.isEmpty()) { |
| 342 for (Entry<String, String> entry : mHeaders.entrySet()) { | 357 for (Entry<String, String> entry : mHeaders.entrySet()) { |
| 343 nativeAddHeader(mUrlRequestAdapter, entry.getKey(), | 358 nativeAddHeader(mUrlRequestAdapter, entry.getKey(), |
| 344 entry.getValue()); | 359 entry.getValue()); |
| 345 } | 360 } |
| 346 } | 361 } |
| 347 | 362 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 377 | 392 |
| 378 @Override | 393 @Override |
| 379 public void cancel() { | 394 public void cancel() { |
| 380 synchronized (mLock) { | 395 synchronized (mLock) { |
| 381 if (mCanceled) { | 396 if (mCanceled) { |
| 382 return; | 397 return; |
| 383 } | 398 } |
| 384 | 399 |
| 385 mCanceled = true; | 400 mCanceled = true; |
| 386 | 401 |
| 387 if (!mRecycled) { | 402 if (mUrlRequestAdapter != 0) { |
| 388 nativeCancel(mUrlRequestAdapter); | 403 nativeCancel(mUrlRequestAdapter); |
| 389 } | 404 } |
| 390 } | 405 } |
| 391 } | 406 } |
| 392 | 407 |
| 393 @Override | 408 @Override |
| 394 public boolean isCanceled() { | 409 public boolean isCanceled() { |
| 395 synchronized (mLock) { | 410 synchronized (mLock) { |
| 396 return mCanceled; | 411 return mCanceled; |
| 397 } | 412 } |
| 398 } | 413 } |
| 399 | 414 |
| 400 public boolean isRecycled() { | |
| 401 synchronized (mLock) { | |
| 402 return mRecycled; | |
| 403 } | |
| 404 } | |
| 405 | |
| 406 @Override | 415 @Override |
| 407 public String getNegotiatedProtocol() { | 416 public String getNegotiatedProtocol() { |
| 408 validateNotRecycled(); | 417 synchronized (mLock) { |
| 409 validateHeadersAvailable(); | 418 validateNativeAdapterNotDestroyed(); |
| 410 return nativeGetNegotiatedProtocol(mUrlRequestAdapter); | 419 validateHeadersAvailable(); |
| 420 return nativeGetNegotiatedProtocol(mUrlRequestAdapter); |
| 421 } |
| 411 } | 422 } |
| 412 | 423 |
| 413 @Override | 424 @Override |
| 414 public String getContentType() { | 425 public String getContentType() { |
| 415 return mContentType; | 426 return mContentType; |
| 416 } | 427 } |
| 417 | 428 |
| 418 @Override | 429 @Override |
| 419 public String getHeader(String name) { | 430 public String getHeader(String name) { |
| 420 validateNotRecycled(); | 431 synchronized (mLock) { |
| 421 validateHeadersAvailable(); | 432 validateNativeAdapterNotDestroyed(); |
| 422 return nativeGetHeader(mUrlRequestAdapter, name); | 433 validateHeadersAvailable(); |
| 434 return nativeGetHeader(mUrlRequestAdapter, name); |
| 435 } |
| 423 } | 436 } |
| 424 | 437 |
| 425 // All response headers. | 438 // All response headers. |
| 426 @Override | 439 @Override |
| 427 public Map<String, List<String>> getAllHeaders() { | 440 public Map<String, List<String>> getAllHeaders() { |
| 428 validateNotRecycled(); | 441 synchronized (mLock) { |
| 429 validateHeadersAvailable(); | 442 validateNativeAdapterNotDestroyed(); |
| 430 ResponseHeadersMap result = new ResponseHeadersMap(); | 443 validateHeadersAvailable(); |
| 431 nativeGetAllHeaders(mUrlRequestAdapter, result); | 444 ResponseHeadersMap result = new ResponseHeadersMap(); |
| 432 return result; | 445 nativeGetAllHeaders(mUrlRequestAdapter, result); |
| 446 return result; |
| 447 } |
| 433 } | 448 } |
| 434 | 449 |
| 435 @Override | 450 @Override |
| 436 public String getUrl() { | 451 public String getUrl() { |
| 437 return mUrl; | 452 return mUrl; |
| 438 } | 453 } |
| 439 | 454 |
| 440 private static int convertRequestPriority(int priority) { | 455 private static int convertRequestPriority(int priority) { |
| 441 switch (priority) { | 456 switch (priority) { |
| 442 case HttpUrlRequest.REQUEST_PRIORITY_IDLE: | 457 case HttpUrlRequest.REQUEST_PRIORITY_IDLE: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 456 | 471 |
| 457 private void onContentLengthOverLimit() { | 472 private void onContentLengthOverLimit() { |
| 458 mContentLengthOverLimit = true; | 473 mContentLengthOverLimit = true; |
| 459 cancel(); | 474 cancel(); |
| 460 } | 475 } |
| 461 | 476 |
| 462 /** | 477 /** |
| 463 * A callback invoked when the response has been fully consumed. | 478 * A callback invoked when the response has been fully consumed. |
| 464 */ | 479 */ |
| 465 private void onRequestComplete() { | 480 private void onRequestComplete() { |
| 481 mErrorCode = nativeGetErrorCode(mUrlRequestAdapter); |
| 482 mErrorString = nativeGetErrorString(mUrlRequestAdapter); |
| 483 // When there is an error or redirects have been disabled, |
| 484 // onResponseStarted is often not invoked. |
| 485 // Populate status code and status text if that's the case. |
| 486 // Note that besides redirects, these two fields may be set on the |
| 487 // request for AUTH and CERT requests. |
| 488 if (mErrorCode != ChromiumUrlRequestError.SUCCESS) { |
| 489 mHttpStatusCode = nativeGetHttpStatusCode(mUrlRequestAdapter); |
| 490 mHttpStatusText = nativeGetHttpStatusText(mUrlRequestAdapter); |
| 491 } |
| 466 mListener.onRequestComplete(this); | 492 mListener.onRequestComplete(this); |
| 467 } | 493 } |
| 468 | 494 |
| 469 private void validateNotRecycled() { | 495 private void validateNativeAdapterNotDestroyed() { |
| 470 if (mRecycled) { | 496 if (mUrlRequestAdapter == 0) { |
| 471 throw new IllegalStateException("Accessing recycled request"); | 497 throw new IllegalStateException("Adapter has been destroyed"); |
| 472 } | 498 } |
| 473 } | 499 } |
| 474 | 500 |
| 475 private void validateNotStarted() { | 501 private void validateNotStarted() { |
| 476 if (mStarted) { | 502 if (mStarted) { |
| 477 throw new IllegalStateException("Request already started"); | 503 throw new IllegalStateException("Request already started"); |
| 478 } | 504 } |
| 479 } | 505 } |
| 480 | 506 |
| 481 private void validateHeadersAvailable() { | 507 private void validateHeadersAvailable() { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 508 "Exception trying to cancel request", cancel_exception); | 534 "Exception trying to cancel request", cancel_exception); |
| 509 } | 535 } |
| 510 } | 536 } |
| 511 | 537 |
| 512 /** | 538 /** |
| 513 * A callback invoked when the first chunk of the response has arrived. | 539 * A callback invoked when the first chunk of the response has arrived. |
| 514 */ | 540 */ |
| 515 @CalledByNative | 541 @CalledByNative |
| 516 private void onResponseStarted() { | 542 private void onResponseStarted() { |
| 517 try { | 543 try { |
| 544 mHttpStatusCode = nativeGetHttpStatusCode(mUrlRequestAdapter); |
| 545 mHttpStatusText = nativeGetHttpStatusText(mUrlRequestAdapter); |
| 518 mContentType = nativeGetContentType(mUrlRequestAdapter); | 546 mContentType = nativeGetContentType(mUrlRequestAdapter); |
| 519 mContentLength = nativeGetContentLength(mUrlRequestAdapter); | 547 mContentLength = nativeGetContentLength(mUrlRequestAdapter); |
| 520 mHeadersAvailable = true; | 548 mHeadersAvailable = true; |
| 521 | 549 |
| 522 if (mContentLengthLimit > 0 | 550 if (mContentLengthLimit > 0 |
| 523 && mContentLength > mContentLengthLimit | 551 && mContentLength > mContentLengthLimit |
| 524 && mCancelIfContentLengthOverLimit) { | 552 && mCancelIfContentLengthOverLimit) { |
| 525 onContentLengthOverLimit(); | 553 onContentLengthOverLimit(); |
| 526 return; | 554 return; |
| 527 } | 555 } |
| 528 | 556 |
| 529 if (mBufferFullResponse && mContentLength != -1 | 557 if (mBufferFullResponse && mContentLength != -1 |
| 530 && !mContentLengthOverLimit) { | 558 && !mContentLengthOverLimit) { |
| 531 ((ChunkedWritableByteChannel) getSink()).setCapacity( | 559 ((ChunkedWritableByteChannel) getSink()).setCapacity( |
| 532 (int) mContentLength); | 560 (int) mContentLength); |
| 533 } | 561 } |
| 534 | 562 |
| 535 if (mOffset != 0) { | 563 if (mOffset != 0) { |
| 536 // The server may ignore the request for a byte range, in which | 564 // The server may ignore the request for a byte range, in which |
| 537 // case status code will be 200, instead of 206. Note that we | 565 // case status code will be 200, instead of 206. Note that we |
| 538 // cannot call getHttpStatusCode as it rewrites 206 into 200. | 566 // cannot call getHttpStatusCode as it rewrites 206 into 200. |
| 539 if (nativeGetHttpStatusCode(mUrlRequestAdapter) == 200) { | 567 if (mHttpStatusCode == 200) { |
| 540 // TODO(mef): Revisit this logic. | 568 // TODO(mef): Revisit this logic. |
| 541 if (mContentLength != -1) { | 569 if (mContentLength != -1) { |
| 542 mContentLength -= mOffset; | 570 mContentLength -= mOffset; |
| 543 } | 571 } |
| 544 mSkippingToOffset = true; | 572 mSkippingToOffset = true; |
| 545 } else { | 573 } else { |
| 546 mSize = mOffset; | 574 mSize = mOffset; |
| 547 } | 575 } |
| 548 } | 576 } |
| 549 mListener.onResponseStarted(this); | 577 mListener.onResponseStarted(this); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 @SuppressWarnings("unused") | 628 @SuppressWarnings("unused") |
| 601 @CalledByNative | 629 @CalledByNative |
| 602 private void finish() { | 630 private void finish() { |
| 603 try { | 631 try { |
| 604 synchronized (mLock) { | 632 synchronized (mLock) { |
| 605 if (mDisableRedirects) { | 633 if (mDisableRedirects) { |
| 606 mHeadersAvailable = true; | 634 mHeadersAvailable = true; |
| 607 } | 635 } |
| 608 mFinished = true; | 636 mFinished = true; |
| 609 | 637 |
| 610 if (mRecycled) { | 638 if (mUrlRequestAdapter == 0) { |
| 611 return; | 639 return; |
| 612 } | 640 } |
| 613 try { | 641 try { |
| 614 mSink.close(); | 642 mSink.close(); |
| 615 } catch (IOException e) { | 643 } catch (IOException e) { |
| 616 // Ignore | 644 // Ignore |
| 617 } | 645 } |
| 618 try { | 646 try { |
| 619 if (mUploadChannel != null && mUploadChannel.isOpen()) { | 647 if (mUploadChannel != null && mUploadChannel.isOpen()) { |
| 620 mUploadChannel.close(); | 648 mUploadChannel.close(); |
| 621 } | 649 } |
| 622 } catch (IOException e) { | 650 } catch (IOException e) { |
| 623 // Ignore | 651 // Ignore |
| 624 } | 652 } |
| 625 onRequestComplete(); | 653 onRequestComplete(); |
| 626 nativeDestroyRequestAdapter(mUrlRequestAdapter); | 654 nativeDestroyRequestAdapter(mUrlRequestAdapter); |
| 627 mUrlRequestAdapter = 0; | 655 mUrlRequestAdapter = 0; |
| 628 mRecycled = true; | |
| 629 } | 656 } |
| 630 } catch (Exception e) { | 657 } catch (Exception e) { |
| 631 mSinkException = new IOException("Exception in finish", e); | 658 mSinkException = new IOException("Exception in finish", e); |
| 632 } | 659 } |
| 633 } | 660 } |
| 634 | 661 |
| 635 /** | 662 /** |
| 636 * Appends header |name| with value |value| to |headersMap|. | 663 * Appends header |name| with value |value| to |headersMap|. |
| 637 */ | 664 */ |
| 638 @SuppressWarnings("unused") | 665 @SuppressWarnings("unused") |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 private native void nativeGetAllHeaders(long urlRequestAdapter, | 747 private native void nativeGetAllHeaders(long urlRequestAdapter, |
| 721 ResponseHeadersMap headers); | 748 ResponseHeadersMap headers); |
| 722 | 749 |
| 723 private native String nativeGetNegotiatedProtocol(long urlRequestAdapter); | 750 private native String nativeGetNegotiatedProtocol(long urlRequestAdapter); |
| 724 | 751 |
| 725 // Explicit class to work around JNI-generator generics confusion. | 752 // Explicit class to work around JNI-generator generics confusion. |
| 726 private static class ResponseHeadersMap extends | 753 private static class ResponseHeadersMap extends |
| 727 HashMap<String, List<String>> { | 754 HashMap<String, List<String>> { |
| 728 } | 755 } |
| 729 } | 756 } |
| OLD | NEW |