001 package com.thetransactioncompany.jsonrpc2.client;
002
003
004 import java.io.BufferedReader;
005 import java.io.InputStream;
006 import java.io.InputStreamReader;
007 import java.io.IOException;
008
009 import java.net.HttpURLConnection;
010
011 import java.util.List;
012 import java.util.Map;
013
014 import java.util.zip.GZIPInputStream;
015 import java.util.zip.Inflater;
016 import java.util.zip.InflaterInputStream;
017
018
019 /**
020 * Represents the raw HTTP response to a JSON-RPC 2.0 request or notification.
021 * Can be used to retrieve the unparsed response content and headers.
022 *
023 * @since 1.6
024 * @author Vladimir Dzhuvinov
025 */
026 public class RawResponse {
027
028
029 /**
030 * The HTTP response headers.
031 */
032 private Map<String,List<String>> headers;
033
034
035 /**
036 * The HTTP response code.
037 */
038 private int statusCode;
039
040
041 /**
042 * The HTTP response message.
043 */
044 private String statusMessage;
045
046
047 /**
048 * The content length.
049 */
050 private int contentLength;
051
052
053 /**
054 * The content type.
055 */
056 private String contentType;
057
058
059 /**
060 * The content encoding.
061 */
062 private String contentEncoding;
063
064
065 /**
066 * The raw HTTP response content.
067 */
068 private String content;
069
070
071 /**
072 * No public instantiation.
073 */
074 private RawResponse() {}
075
076
077 /**
078 * Parses the raw HTTP response from the specified URL connection.
079 *
080 * @param connection The URL connection, must be in state completed and
081 * not {@code null}.
082 *
083 * @throws IOException If the response content couldn't be read.
084 */
085 protected static RawResponse parse(final HttpURLConnection connection)
086 throws IOException {
087
088 // Check for HTTP compression
089 String encoding = connection.getContentEncoding();
090
091 InputStream is;
092
093 if (encoding != null && encoding.equalsIgnoreCase("gzip"))
094 is = new GZIPInputStream(connection.getInputStream());
095
096 else if (encoding != null && encoding.equalsIgnoreCase("deflate"))
097 is = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
098
099 else
100 is = connection.getInputStream();
101
102
103 // Read the response content
104 StringBuilder responseText = new StringBuilder();
105
106 BufferedReader input = new BufferedReader(new InputStreamReader(is, "UTF-8"));
107
108 String line;
109
110 while ((line = input.readLine()) != null) {
111 responseText.append(line);
112 responseText.append(System.getProperty("line.separator"));
113 }
114
115 input.close();
116
117 RawResponse response = new RawResponse();
118
119 response.content = responseText.toString();
120
121 // Save HTTP code + message
122 response.statusCode = connection.getResponseCode();
123 response.statusMessage = connection.getResponseMessage();
124
125 // Save headers
126 response.headers = connection.getHeaderFields();
127
128 response.contentLength = connection.getContentLength();
129 response.contentType = connection.getContentType();
130 response.contentEncoding = encoding;
131
132 return response;
133 }
134
135
136 /**
137 * Gets the status code from the HTTP response message, e.g. 200 on
138 * success.
139 *
140 * @return The HTTP status code, or -1.
141 */
142 public int getStatusCode() {
143
144 return statusCode;
145 }
146
147
148 /**
149 * Gets the HTTP response status message, if any, returned along with
150 * the status code from a server.
151 *
152 * @return The HTTP status message, or {@code null}.
153 */
154 public String getStatusMessage() {
155
156 return statusMessage;
157 }
158
159
160 /**
161 * Returns the raw response content.
162 *
163 * @return The raw content.
164 */
165 public String getContent() {
166
167 return content;
168 }
169
170
171 /**
172 * Returns an unmodifiable Map of the header fields. The Map keys are
173 * Strings that represent the response header field names. Each Map
174 * value is an unmodifiable List of Strings that represents the
175 * corresponding field values.
176 *
177 * @return A Map of the header fields.
178 */
179 public Map<String,List<String>> getHeaderFields() {
180
181 return headers;
182 }
183
184
185 /**
186 * Returns the value of the named header field. If called on a
187 * connection that sets the same header multiple times with possibly
188 * different values, only the last value is returned.
189 *
190 * @param name The name of the header.
191 *
192 * @return The value of the named header field, {@code null} if there
193 * is no such field in the header.
194 */
195 public String getHeaderField(final String name) {
196
197 List <String> values = headers.get(name);
198
199 if (values == null | values.size() <= 0)
200 return null;
201
202 return values.get(0);
203 }
204
205
206 /**
207 * Returns the value of the "Content-Length" header field.
208 *
209 * @return The content length of the response, or -1 if the content
210 * length is not known.
211 */
212 public int getContentLength() {
213
214 return contentLength;
215 }
216
217
218 /**
219 * Returns the value of the "Content-Type" header field.
220 *
221 * @return The content type of the response, or {@code null} if not
222 * known.
223 */
224 public String getContentType() {
225
226 return contentType;
227 }
228
229 /**
230 * Returns the value of the "Content-Encoding" header field.
231 *
232 * @return The content encoding of the response, or {@code null} if not
233 * known.
234 */
235 public String getContentEncoding() {
236
237 return contentEncoding;
238 }
239 }