001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.client;
018
019import java.io.UnsupportedEncodingException;
020import java.nio.charset.Charset;
021import java.nio.charset.StandardCharsets;
022
023import org.springframework.http.HttpHeaders;
024import org.springframework.lang.Nullable;
025
026/**
027 * Common base class for exceptions that contain actual HTTP response data.
028 *
029 * @author Rossen Stoyanchev
030 * @since 4.3
031 */
032public class RestClientResponseException extends RestClientException {
033
034        private static final long serialVersionUID = -8803556342728481792L;
035
036        private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
037
038
039        private final int rawStatusCode;
040
041        private final String statusText;
042
043        private final byte[] responseBody;
044
045        @Nullable
046        private final HttpHeaders responseHeaders;
047
048        @Nullable
049        private final String responseCharset;
050
051
052        /**
053         * Construct a new instance of with the given response data.
054         * @param statusCode the raw status code value
055         * @param statusText the status text
056         * @param responseHeaders the response headers (may be {@code null})
057         * @param responseBody the response body content (may be {@code null})
058         * @param responseCharset the response body charset (may be {@code null})
059         */
060        public RestClientResponseException(String message, int statusCode, String statusText,
061                        @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
062
063                super(message);
064                this.rawStatusCode = statusCode;
065                this.statusText = statusText;
066                this.responseHeaders = responseHeaders;
067                this.responseBody = (responseBody != null ? responseBody : new byte[0]);
068                this.responseCharset = (responseCharset != null ? responseCharset.name() : null);
069        }
070
071
072        /**
073         * Return the raw HTTP status code value.
074         */
075        public int getRawStatusCode() {
076                return this.rawStatusCode;
077        }
078
079        /**
080         * Return the HTTP status text.
081         */
082        public String getStatusText() {
083                return this.statusText;
084        }
085
086        /**
087         * Return the HTTP response headers.
088         */
089        @Nullable
090        public HttpHeaders getResponseHeaders() {
091                return this.responseHeaders;
092        }
093
094        /**
095         * Return the response body as a byte array.
096         */
097        public byte[] getResponseBodyAsByteArray() {
098                return this.responseBody;
099        }
100
101        /**
102         * Return the response body converted to String. The charset used is that
103         * of the response "Content-Type" or otherwise {@code "UTF-8"}.
104         */
105        public String getResponseBodyAsString() {
106                return getResponseBodyAsString(DEFAULT_CHARSET);
107        }
108
109        /**
110         * Return the response body converted to String. The charset used is that
111         * of the response "Content-Type" or otherwise the one given.
112         * @param fallbackCharset the charset to use on if the response doesn't specify.
113         * @since 5.1.11
114         */
115        public String getResponseBodyAsString(Charset fallbackCharset) {
116                if (this.responseCharset == null) {
117                        return new String(this.responseBody, fallbackCharset);
118                }
119                try {
120                        return new String(this.responseBody, this.responseCharset);
121                }
122                catch (UnsupportedEncodingException ex) {
123                        // should not occur
124                        throw new IllegalStateException(ex);
125                }
126        }
127
128}