// Copyright (c) 2003-present, Jodd Team (http://jodd.org) // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package jodd.http; import jodd.io.StreamUtil; import jodd.util.StringPool; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.zip.GZIPInputStream; import static jodd.util.StringPool.CRLF; import static jodd.util.StringPool.SPACE; /** * HTTP response. */ public class HttpResponse extends HttpBase<HttpResponse> { protected int statusCode; protected String statusPhrase; /** * Returns response status code. */ public int statusCode() { return statusCode; } /** * Sets response status code. */ public HttpResponse statusCode(int statusCode) { this.statusCode = statusCode; return this; } /** * Returns response status phrase. */ public String statusPhrase() { return statusPhrase; } /** * Sets response status phrase. */ public HttpResponse statusPhrase(String statusPhrase) { this.statusPhrase = statusPhrase; return this; } // ---------------------------------------------------------------- cookie /** * Returns list of valid cookies sent from server. * If no cookie found, returns an empty array. Invalid cookies are ignored. */ public Cookie[] cookies() { List<String> newCookies = headers("set-cookie"); if (newCookies == null) { return new Cookie[0]; } List<Cookie> cookieList = new ArrayList<>(newCookies.size()); for (String cookieValue : newCookies) { try { Cookie cookie = new Cookie(cookieValue); cookieList.add(cookie); } catch (Exception ex) { // ignore } } return cookieList.toArray(new Cookie[cookieList.size()]); } // ---------------------------------------------------------------- body /** * Unzips GZip-ed body content, removes the content-encoding header * and sets the new content-length value. */ public HttpResponse unzip() { String contentEncoding = contentEncoding(); if (contentEncoding != null && contentEncoding().equals("gzip")) { if (body != null) { removeHeader(HEADER_CONTENT_ENCODING); try { ByteArrayInputStream in = new ByteArrayInputStream(body.getBytes(StringPool.ISO_8859_1)); GZIPInputStream gzipInputStream = new GZIPInputStream(in); ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamUtil.copy(gzipInputStream, out); body(out.toString(StringPool.ISO_8859_1)); } catch (IOException ioex) { throw new HttpException(ioex); } } } return this; } // ---------------------------------------------------------------- buffer /** * Creates response {@link jodd.http.Buffer buffer}. */ @Override protected Buffer buffer(boolean fullResponse) { // form Buffer formBuffer = formBuffer(); // response Buffer response = new Buffer(); response.append(httpVersion) .append(SPACE) .append(statusCode) .append(SPACE) .append(statusPhrase) .append(CRLF); populateHeaderAndBody(response, formBuffer, fullResponse); return response; } // ---------------------------------------------------------------- read from /** * Reads response input stream and returns {@link HttpResponse response}. * Supports both streamed and chunked response. */ public static HttpResponse readFrom(InputStream in) { InputStreamReader inputStreamReader; try { inputStreamReader = new InputStreamReader(in, StringPool.ISO_8859_1); } catch (UnsupportedEncodingException ignore) { return null; } BufferedReader reader = new BufferedReader(inputStreamReader); HttpResponse httpResponse = new HttpResponse(); // the first line String line; try { line = reader.readLine(); } catch (IOException ioex) { throw new HttpException(ioex); } if (line != null) { line = line.trim(); int ndx = line.indexOf(' '); int ndx2; if (ndx > -1) { httpResponse.httpVersion(line.substring(0, ndx)); ndx2 = line.indexOf(' ', ndx + 1); } else { httpResponse.httpVersion(HTTP_1_1); ndx2 = -1; ndx = 0; } if (ndx2 == -1) { ndx2 = line.length(); } try { httpResponse.statusCode(Integer.parseInt(line.substring(ndx, ndx2).trim())); } catch (NumberFormatException nfex) { httpResponse.statusCode(-1); } httpResponse.statusPhrase(line.substring(ndx2).trim()); } httpResponse.readHeaders(reader); httpResponse.readBody(reader); return httpResponse; } // ---------------------------------------------------------------- request protected HttpRequest httpRequest; /** * Binds {@link jodd.http.HttpRequest} to this response. */ void assignHttpRequest(HttpRequest httpRequest) { this.httpRequest = httpRequest; } /** * Returns {@link jodd.http.HttpRequest} that created this response. */ public HttpRequest getHttpRequest() { return httpRequest; } /** * Closes requests connection if it was open. * Should be called when using keep-alive connections. * Otherwise, connection will be already closed. */ public HttpResponse close() { HttpConnection httpConnection = httpRequest.httpConnection; if (httpConnection != null) { httpConnection.close(); httpRequest.httpConnection = null; } return this; } }