LEFT | RIGHT |
1 /* | 1 /* |
2 * Copyright (c) 2010 Google Inc. | 2 * Copyright (c) 2010 Google Inc. |
3 * | 3 * |
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not u
se this file except | 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not u
se this file except |
5 * in compliance with the License. You may obtain a copy of the License at | 5 * in compliance with the License. You may obtain a copy of the License at |
6 * | 6 * |
7 * http://www.apache.org/licenses/LICENSE-2.0 | 7 * http://www.apache.org/licenses/LICENSE-2.0 |
8 * | 8 * |
9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License | 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express | 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 | 704 |
705 /** | 705 /** |
706 * Execute the HTTP request and returns the HTTP response. | 706 * Execute the HTTP request and returns the HTTP response. |
707 * <p> | 707 * <p> |
708 * Note that regardless of the returned status code, the HTTP response content
has not been parsed | 708 * Note that regardless of the returned status code, the HTTP response content
has not been parsed |
709 * yet, and must be parsed by the calling code. | 709 * yet, and must be parsed by the calling code. |
710 * <p> | 710 * <p> |
711 * Almost all details of the request and response are logged if {@link Level#C
ONFIG} is loggable. | 711 * Almost all details of the request and response are logged if {@link Level#C
ONFIG} is loggable. |
712 * The only exception is the value of the {@code Authorization} header which i
s only logged if | 712 * The only exception is the value of the {@code Authorization} header which i
s only logged if |
713 * {@link Level#ALL} is loggable. | 713 * {@link Level#ALL} is loggable. |
| 714 * <p> |
| 715 * Callers should call {@link HttpResponse#disconnect} when the returned HTTP
response object is |
| 716 * no longer needed. However, {@link HttpResponse#disconnect} does not have to
be called if the |
| 717 * response stream is properly closed. Example usage: |
| 718 * </p> |
| 719 * |
| 720 * <pre> |
| 721 HttpResponse response = request.execute(); |
| 722 try { |
| 723 // process the HTTP response object |
| 724 } finally { |
| 725 response.disconnect(); |
| 726 } |
| 727 * </pre> |
714 * | 728 * |
715 * @return HTTP response for an HTTP success response (or HTTP error response
if | 729 * @return HTTP response for an HTTP success response (or HTTP error response
if |
716 * {@link #getThrowExceptionOnExecuteError()} is {@code false}) | 730 * {@link #getThrowExceptionOnExecuteError()} is {@code false}) |
717 * @throws HttpResponseException for an HTTP error response (only if | 731 * @throws HttpResponseException for an HTTP error response (only if |
718 * {@link #getThrowExceptionOnExecuteError()} is {@code true}) | 732 * {@link #getThrowExceptionOnExecuteError()} is {@code true}) |
719 * @see HttpResponse#isSuccessStatusCode() | 733 * @see HttpResponse#isSuccessStatusCode() |
720 */ | 734 */ |
721 public HttpResponse execute() throws IOException { | 735 public HttpResponse execute() throws IOException { |
722 boolean retrySupported = false; | 736 boolean retrySupported = false; |
723 Preconditions.checkArgument(numRetries >= 0); | 737 Preconditions.checkArgument(numRetries >= 0); |
724 int retriesRemaining = numRetries; | 738 int retriesRemaining = numRetries; |
725 if (backOffPolicy != null) { | 739 if (backOffPolicy != null) { |
726 // Reset the BackOffPolicy at the start of each execute. | 740 // Reset the BackOffPolicy at the start of each execute. |
727 backOffPolicy.reset(); | 741 backOffPolicy.reset(); |
728 } | 742 } |
729 HttpResponse response = null; | 743 HttpResponse response = null; |
730 IOException executeException; | 744 IOException executeException; |
731 LowLevelHttpRequest lowLevelHttpRequest; | |
732 | 745 |
733 Preconditions.checkNotNull(method); | 746 Preconditions.checkNotNull(method); |
734 Preconditions.checkNotNull(url); | 747 Preconditions.checkNotNull(url); |
735 | 748 |
736 do { | 749 do { |
737 // Cleanup any unneeded response from a previous iteration | 750 // Cleanup any unneeded response from a previous iteration |
738 if (response != null) { | 751 if (response != null) { |
739 response.ignore(); | 752 response.ignore(); |
740 } | 753 } |
741 | 754 |
742 response = null; | 755 response = null; |
743 executeException = null; | 756 executeException = null; |
744 | 757 |
745 // run the interceptor | 758 // run the interceptor |
746 if (interceptor != null) { | 759 if (interceptor != null) { |
747 interceptor.intercept(this); | 760 interceptor.intercept(this); |
748 } | 761 } |
749 // build low-level HTTP request | 762 // build low-level HTTP request |
750 String urlString = url.build(); | 763 String urlString = url.build(); |
| 764 LowLevelHttpRequest lowLevelHttpRequest; |
751 switch (method) { | 765 switch (method) { |
752 case DELETE: | 766 case DELETE: |
753 lowLevelHttpRequest = transport.buildDeleteRequest(urlString); | 767 lowLevelHttpRequest = transport.buildDeleteRequest(urlString); |
754 break; | 768 break; |
755 default: | 769 default: |
756 lowLevelHttpRequest = transport.buildGetRequest(urlString); | 770 lowLevelHttpRequest = transport.buildGetRequest(urlString); |
757 break; | 771 break; |
758 case HEAD: | 772 case HEAD: |
759 Preconditions.checkArgument( | 773 Preconditions.checkArgument( |
760 transport.supportsHead(), "HTTP transport doesn't support HEAD"); | 774 transport.supportsHead(), "HTTP transport doesn't support HEAD"); |
(...skipping 14 matching lines...) Expand all Loading... |
775 Logger logger = HttpTransport.LOGGER; | 789 Logger logger = HttpTransport.LOGGER; |
776 boolean loggable = loggingEnabled && logger.isLoggable(Level.CONFIG); | 790 boolean loggable = loggingEnabled && logger.isLoggable(Level.CONFIG); |
777 StringBuilder logbuf = null; | 791 StringBuilder logbuf = null; |
778 // log method and URL | 792 // log method and URL |
779 if (loggable) { | 793 if (loggable) { |
780 logbuf = new StringBuilder(); | 794 logbuf = new StringBuilder(); |
781 logbuf.append("-------------- REQUEST --------------").append(StringUti
ls.LINE_SEPARATOR); | 795 logbuf.append("-------------- REQUEST --------------").append(StringUti
ls.LINE_SEPARATOR); |
782 logbuf.append(method).append(' ').append(urlString).append(StringUtils.L
INE_SEPARATOR); | 796 logbuf.append(method).append(' ').append(urlString).append(StringUtils.L
INE_SEPARATOR); |
783 } | 797 } |
784 // add to user agent | 798 // add to user agent |
785 if (headers.getUserAgent() == null) { | 799 String originalUserAgent = headers.getUserAgent(); |
| 800 if (originalUserAgent == null) { |
786 headers.setUserAgent(USER_AGENT_SUFFIX); | 801 headers.setUserAgent(USER_AGENT_SUFFIX); |
787 } else { | 802 } else { |
788 headers.setUserAgent(headers.getUserAgent() + " " + USER_AGENT_SUFFIX); | 803 headers.setUserAgent(originalUserAgent + " " + USER_AGENT_SUFFIX); |
789 } | 804 } |
790 // headers | 805 // headers |
791 HttpHeaders.serializeHeaders(headers, logbuf, logger, lowLevelHttpRequest)
; | 806 HttpHeaders.serializeHeaders(headers, logbuf, logger, lowLevelHttpRequest)
; |
| 807 // set the original user agent back to the headers so that retries do not
keep appending to it |
| 808 headers.setUserAgent(originalUserAgent); |
792 | 809 |
793 // content | 810 // content |
794 HttpContent content = this.content; | 811 HttpContent content = this.content; |
795 if (!isAllowEmptyContent() | 812 if (!isAllowEmptyContent() |
796 && (method == HttpMethod.PUT || method == HttpMethod.POST || method ==
HttpMethod.PATCH) | 813 && (method == HttpMethod.PUT || method == HttpMethod.POST || method ==
HttpMethod.PATCH) |
797 && (content == null || content.getLength() == 0)) { | 814 && (content == null || content.getLength() == 0)) { |
798 content = ByteArrayContent.fromString(null, " "); | 815 content = ByteArrayContent.fromString(null, " "); |
799 } | 816 } |
800 if (content != null) { | 817 if (content != null) { |
801 String contentEncoding = content.getEncoding(); | 818 String contentEncoding = content.getEncoding(); |
(...skipping 30 matching lines...) Expand all Loading... |
832 logger.config(logbuf.toString()); | 849 logger.config(logbuf.toString()); |
833 } | 850 } |
834 | 851 |
835 // We need to make sure our content type can support retry | 852 // We need to make sure our content type can support retry |
836 // null content is inherently able to be retried | 853 // null content is inherently able to be retried |
837 retrySupported = retriesRemaining > 0 && (content == null || content.retry
Supported()); | 854 retrySupported = retriesRemaining > 0 && (content == null || content.retry
Supported()); |
838 | 855 |
839 // execute | 856 // execute |
840 lowLevelHttpRequest.setTimeout(connectTimeout, readTimeout); | 857 lowLevelHttpRequest.setTimeout(connectTimeout, readTimeout); |
841 try { | 858 try { |
842 response = new HttpResponse(this, lowLevelHttpRequest.execute()); | 859 LowLevelHttpResponse lowLevelHttpResponse = lowLevelHttpRequest.execute(
); |
| 860 // Flag used to indicate if an exception is thrown before the response i
s constructed. |
| 861 boolean responseConstructed = false; |
| 862 try { |
| 863 response = new HttpResponse(this, lowLevelHttpResponse); |
| 864 responseConstructed = true; |
| 865 } finally { |
| 866 if (!responseConstructed) { |
| 867 lowLevelHttpResponse.getContent().close(); |
| 868 } |
| 869 } |
843 } catch (IOException e) { | 870 } catch (IOException e) { |
844 if (!retryOnExecuteIOException) { | 871 if (!retryOnExecuteIOException) { |
845 lowLevelHttpRequest.disconnect(); | |
846 throw e; | 872 throw e; |
847 } | 873 } |
848 // Save the exception in case the retries do not work and we need to re-
throw it later. | 874 // Save the exception in case the retries do not work and we need to re-
throw it later. |
849 executeException = e; | 875 executeException = e; |
850 logger.log(Level.WARNING, e.getMessage(), e); | 876 logger.log(Level.WARNING, e.getMessage(), e); |
851 } | 877 } |
852 | 878 |
853 if (response != null && !response.isSuccessStatusCode()) { | 879 // Flag used to indicate if an exception is thrown before the response has
completed |
854 boolean errorHandled = false; | 880 // processing. |
855 boolean redirectRequest = false; | 881 boolean responseProcessed = false; |
856 boolean backOffRetry = false; | 882 try { |
857 if (unsuccessfulResponseHandler != null) { | 883 if (response != null && !response.isSuccessStatusCode()) { |
858 // Even if we don't have the potential to retry, we might want to run
the | 884 boolean errorHandled = false; |
859 // handler to fix conditions (like expired tokens) that might cause us | 885 boolean redirectRequest = false; |
860 // trouble on our next request | 886 boolean backOffRetry = false; |
861 errorHandled = unsuccessfulResponseHandler.handleResponse(this, respon
se, retrySupported); | 887 if (unsuccessfulResponseHandler != null) { |
862 } | 888 // Even if we don't have the potential to retry, we might want to ru
n the |
863 if (!errorHandled) { | 889 // handler to fix conditions (like expired tokens) that might cause
us |
864 if (getFollowRedirects() && isRedirected(response)) { | 890 // trouble on our next request |
865 // The unsuccessful request's error could not be handled and it is a
redirect request. | 891 errorHandled = |
866 handleRedirect(response); | 892 unsuccessfulResponseHandler.handleResponse(this, response, retry
Supported); |
867 redirectRequest = true; | 893 } |
868 } else if (retrySupported && backOffPolicy != null | 894 if (!errorHandled) { |
869 && backOffPolicy.isBackOffRequired(response.getStatusCode())) { | 895 if (getFollowRedirects() && isRedirected(response)) { |
870 // The unsuccessful request's error could not be handled and should
be backed off before | 896 // The unsuccessful request's error could not be handled and it is
a redirect request. |
871 // retrying. | 897 handleRedirect(response); |
872 long backOffTime = backOffPolicy.getNextBackOffMillis(); | 898 redirectRequest = true; |
873 if (backOffTime != BackOffPolicy.STOP) { | 899 } else if (retrySupported && backOffPolicy != null |
874 sleep(backOffTime); | 900 && backOffPolicy.isBackOffRequired(response.getStatusCode())) { |
875 backOffRetry = true; | 901 // The unsuccessful request's error could not be handled and shoul
d be backed off |
| 902 // before |
| 903 // retrying. |
| 904 long backOffTime = backOffPolicy.getNextBackOffMillis(); |
| 905 if (backOffTime != BackOffPolicy.STOP) { |
| 906 sleep(backOffTime); |
| 907 backOffRetry = true; |
| 908 } |
876 } | 909 } |
877 } | 910 } |
| 911 // A retry is required if the error was successfully handled or if it
is a redirect |
| 912 // request |
| 913 // or if the back off policy determined a retry is necessary. |
| 914 retrySupported &= (errorHandled || redirectRequest || backOffRetry); |
| 915 // need to close the response stream before retrying a request |
| 916 if (retrySupported) { |
| 917 response.ignore(); |
| 918 } |
| 919 } else { |
| 920 // Retry is not required for a successful status code unless the respo
nse is null. |
| 921 retrySupported &= (response == null); |
878 } | 922 } |
879 // A retry is required if the error was successfully handled or if it is
a redirect request | 923 // Once there are no more retries remaining, this will be -1 |
880 // or if the back off policy determined a retry is necessary. | 924 // Count redirects as retries, we want a finite limit of redirects. |
881 retrySupported &= (errorHandled || redirectRequest || backOffRetry); | 925 retriesRemaining--; |
882 // need to close the response stream before retrying a request | 926 |
883 if (retrySupported) { | 927 responseProcessed = true; |
884 response.ignore(); | 928 } finally { |
| 929 if (response != null && !responseProcessed) { |
| 930 response.disconnect(); |
885 } | 931 } |
886 } else { | 932 } |
887 // Retry is not required for a successful status code unless the respons
e is null. | |
888 retrySupported &= (response == null); | |
889 } | |
890 // Once there are no more retries remaining, this will be -1 | |
891 // Count redirects as retries, we want a finite limit of redirects. | |
892 retriesRemaining--; | |
893 } while (retrySupported); | 933 } while (retrySupported); |
894 | |
895 // Disconnect the request at this point. | |
896 lowLevelHttpRequest.disconnect(); | |
897 | 934 |
898 if (response == null) { | 935 if (response == null) { |
899 // Retries did not help resolve the execute exception, re-throw it. | 936 // Retries did not help resolve the execute exception, re-throw it. |
900 throw executeException; | 937 throw executeException; |
901 } | 938 } |
902 | 939 |
903 if (throwExceptionOnExecuteError && !response.isSuccessStatusCode()) { | 940 if (throwExceptionOnExecuteError && !response.isSuccessStatusCode()) { |
904 throw new HttpResponseException(response); | 941 try { |
| 942 throw new HttpResponseException(response); |
| 943 } finally { |
| 944 response.disconnect(); |
| 945 } |
905 } | 946 } |
906 return response; | 947 return response; |
907 } | 948 } |
908 | 949 |
909 /** | 950 /** |
910 * Sets up this request object to handle the necessary redirect. | 951 * Sets up this request object to handle the necessary redirect. |
911 */ | 952 */ |
912 private void handleRedirect(HttpResponse response) { | 953 private void handleRedirect(HttpResponse response) { |
913 String redirectLocation = response.getHeaders().getLocation(); | 954 String redirectLocation = response.getHeaders().getLocation(); |
914 setUrl(new GenericUrl(redirectLocation)); | 955 setUrl(new GenericUrl(redirectLocation)); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 * @since 1.4 | 1003 * @since 1.4 |
963 */ | 1004 */ |
964 public static String normalizeMediaType(String mediaType) { | 1005 public static String normalizeMediaType(String mediaType) { |
965 if (mediaType == null) { | 1006 if (mediaType == null) { |
966 return null; | 1007 return null; |
967 } | 1008 } |
968 int semicolon = mediaType.indexOf(';'); | 1009 int semicolon = mediaType.indexOf(';'); |
969 return semicolon == -1 ? mediaType : mediaType.substring(0, semicolon); | 1010 return semicolon == -1 ? mediaType : mediaType.substring(0, semicolon); |
970 } | 1011 } |
971 } | 1012 } |
LEFT | RIGHT |