/* * Copyright 2015 Odnoklassniki Ltd, Mail.Ru Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package one.nio.http; import one.nio.util.ByteArrayBuilder; import one.nio.util.Utf8; import java.nio.charset.Charset; import java.util.Arrays; public class Response { public static final String CONTINUE = "100 Continue"; public static final String SWITCHING_PROTOCOLS = "101 Switching Protocols"; public static final String OK = "200 OK"; public static final String CREATED = "201 Created"; public static final String ACCEPTED = "202 Accepted"; public static final String NON_AUTHORITATIVE_INFORMATION = "203 Non-Authoritative Information"; public static final String NO_CONTENT = "204 No Content"; public static final String RESET_CONTENT = "205 Reset Content"; public static final String PARTIAL_CONTENT = "206 Partial Content"; public static final String MULTIPLE_CHOICES = "300 Multiple Choices"; public static final String MOVED_PERMANENTLY = "301 Moved Permanently"; public static final String FOUND = "302 Found"; public static final String SEE_OTHER = "303 See Other"; public static final String NOT_MODIFIED = "304 Not Modified"; public static final String USE_PROXY = "305 Use Proxy"; public static final String TEMPORARY_REDIRECT = "307 Temporary Redirect"; public static final String BAD_REQUEST = "400 Bad Request"; public static final String UNAUTHORIZED = "401 Unauthorized"; public static final String PAYMENT_REQUIRED = "402 Payment Required"; public static final String FORBIDDEN = "403 Forbidden"; public static final String NOT_FOUND = "404 Not Found"; public static final String METHOD_NOT_ALLOWED = "405 Method Not Allowed"; public static final String NOT_ACCEPTABLE = "406 Not Acceptable"; public static final String PROXY_AUTHENTICATION_REQUIRED = "407 Proxy Authentication Required"; public static final String REQUEST_TIMEOUT = "408 Request Timeout"; public static final String CONFLICT = "409 Conflict"; public static final String GONE = "410 Gone"; public static final String LENGTH_REQUIRED = "411 Length Required"; public static final String PRECONDITION_FAILED = "412 Precondition Failed"; public static final String REQUEST_ENTITY_TOO_LARGE = "413 Request Entity Too Large"; public static final String REQUEST_URI_TOO_LONG = "414 Request-URI Too Long"; public static final String UNSUPPORTED_MEDIA_TYPE = "415 Unsupported Media Type"; public static final String REQUESTED_RANGE_NOT_SATISFIABLE = "416 Requested Range Not Satisfiable"; public static final String EXPECTATION_FAILED = "417 Expectation Failed"; public static final String INTERNAL_ERROR = "500 Internal Server Error"; public static final String NOT_IMPLEMENTED = "501 Not Implemented"; public static final String BAD_GATEWAY = "502 Bad Gateway"; public static final String SERVICE_UNAVAILABLE = "503 Service Unavailable"; public static final String GATEWAY_TIMEOUT = "504 Gateway Timeout"; public static final String HTTP_VERSION_NOT_SUPPORTED = "505 HTTP Version Not Supported"; public static final byte[] EMPTY = new byte[0]; private static final byte[] HTTP11_HEADER = Utf8.toBytes("HTTP/1.1 "); private static final int PROTOCOL_HEADER_LENGTH = 11; private static final Charset UTF8 = Charset.forName("UTF-8"); private int headerCount; private String[] headers; private byte[] body; public Response(String resultCode) { this.headerCount = 1; this.headers = new String[4]; this.headers[0] = resultCode; } public Response(String resultCode, byte[] body) { this.headerCount = 2; this.headers = new String[4]; this.headers[0] = resultCode; this.headers[1] = "Content-Length: " + body.length; this.body = body; } public Response(Response prototype) { this.headerCount = prototype.headerCount; this.headers = Arrays.copyOf(prototype.headers, prototype.headerCount + 4); this.body = prototype.body; } public static Response ok(byte[] body) { return new Response(OK, body); } public static Response ok(String plainText) { Response response = new Response(OK, plainText.getBytes(UTF8)); response.addHeader("Content-Type: text/plain; charset=utf-8"); return response; } public static Response redirect(String url) { Response response = new Response(FOUND, EMPTY); response.addHeader("Location: " + url); return response; } public void addHeader(String header) { if (headerCount >= headers.length) { headers = Arrays.copyOf(headers, headers.length + 4); } headers[headerCount++] = header; } public int getHeaderCount() { return headerCount; } public String[] getHeaders() { return headers; } public int getStatus() { String s = headers[0]; return (s.charAt(0) * 100) + (s.charAt(1) * 10) + s.charAt(2) - ('0' * 111); } public String getHeader(String key) { int keyLength = key.length(); for (int i = 1; i < headerCount; i++) { if (headers[i].regionMatches(true, 0, key, 0, keyLength)) { return headers[i].substring(keyLength); } } return null; } public byte[] getBody() { return body; } public void setBody(byte[] body) { this.body = body; } public String getBodyUtf8() { return body == null ? null : new String(body, UTF8); } public byte[] toBytes(boolean includeBody) { int estimatedSize = PROTOCOL_HEADER_LENGTH + headerCount * 2; for (int i = 0; i < headerCount; i++) { estimatedSize += headers[i].length(); } if (includeBody && body != null) { estimatedSize += body.length; } ByteArrayBuilder builder = new ByteArrayBuilder(estimatedSize); builder.append(HTTP11_HEADER); for (int i = 0; i < headerCount; i++) { builder.append(headers[i]).append('\r').append('\n'); } builder.append('\r').append('\n'); if (includeBody && body != null) { builder.append(body); } return builder.buffer(); } @Override public String toString() { return new String(toBytes(true), UTF8); } }