Java tutorial
/* * Copyright (C) 2013 "Erhan Bagdemir" * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.bagdemir.eboda.utils; import static com.bagdemir.eboda.utils.Statics.HTTP_BAD_REQUEST; import static com.bagdemir.eboda.utils.Statics.HTTP_CONNECTION; import static com.bagdemir.eboda.utils.Statics.HTTP_CONTENT_LENGTH; import static com.bagdemir.eboda.utils.Statics.HTTP_CONTENT_TYPE; import static com.bagdemir.eboda.utils.Statics.HTTP_ETAG; import static com.bagdemir.eboda.utils.Statics.HTTP_GET; import static com.bagdemir.eboda.utils.Statics.HTTP_HEAD; import static com.bagdemir.eboda.utils.Statics.HTTP_KEEP_ALIVE; import static com.bagdemir.eboda.utils.Statics.HTTP_MIME_TEXT_PLAIN; import static com.bagdemir.eboda.utils.Statics.HTTP_NOT_FOUND; import static com.bagdemir.eboda.utils.Statics.HTTP_NOT_IMPLEMENTED; import static com.bagdemir.eboda.utils.Statics.HTTP_NOT_MODIFIED; import static com.bagdemir.eboda.utils.Statics.HTTP_OK; import static com.bagdemir.eboda.utils.Statics.HTTP_POST; import static com.bagdemir.eboda.utils.Statics.HTTP_PRECONDITION_FAILED; import static com.bagdemir.eboda.utils.Statics.UTF_8; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.bagdemir.eboda.ext.CacheManager; import com.bagdemir.eboda.resource.DirectoryResource; import com.bagdemir.eboda.resource.FileResource; import com.bagdemir.eboda.resource.Resource; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; /** * Some utility methods in order to process an HTTP request. */ public class HttpUtils { private static final Logger LOGGER = Logger.getLogger(HttpUtils.class); /** * The method returns whether the client sends Keep-Alive or not. * * @param httpExchange exchange object. * @return whether request headers contains Keep-Alive */ public static boolean isKeepAlive(final HttpExchange httpExchange) { final Headers requestHeaders = httpExchange.getRequestHeaders(); if (requestHeaders != null) { final List<String> connectionHeader = requestHeaders.get(HTTP_CONNECTION); if (CollectionUtils.isNotEmpty(connectionHeader) && isKeepAlive(connectionHeader)) { return true; } } return false; } private static boolean isKeepAlive(final List<String> connectionHeader) { return connectionHeader.get(0).trim().equalsIgnoreCase(Statics.HTTP_KEEP_ALIVE); } public static boolean isHeadRequest(final HttpExchange httpExchange) { return httpExchange.getRequestMethod().equalsIgnoreCase(HTTP_HEAD); } public static boolean isGetRequest(final HttpExchange httpExchange) { return httpExchange.getRequestMethod().equalsIgnoreCase(HTTP_GET); } public static boolean isPostRequest(final HttpExchange httpExchange) { return httpExchange.getRequestMethod().equalsIgnoreCase(HTTP_POST); } public static String getPathVariable(final HttpExchange httpExchange) { final String requestedUri = httpExchange.getRequestURI().toString(); int posHttpQuery = requestedUri.indexOf("?"); if (posHttpQuery >= 0) { return ServerUtils.urlDecode(requestedUri.substring(0, posHttpQuery)); } return ServerUtils.urlDecode(requestedUri); } public static void responseWith200(final HttpExchange httpExchange, final Resource resource, final boolean headRequest) { final Map<String, String> headerInfo = new HashMap<>(); headerInfo.put(HTTP_CONTENT_TYPE, resource.getContentType()); headerInfo.put(HTTP_ETAG, CacheManager.newInstance().getETag(resource)); /* keep alive behavior is default in HTTP 1.1. For the clients which don't support HTTP 1.1 yet, always send Keep-Alive headers. * */ if (isKeepAlive(httpExchange)) { headerInfo.put(HTTP_CONNECTION, HTTP_KEEP_ALIVE); headerInfo.put(HTTP_CONTENT_LENGTH, getContentLength(resource)); } sendHttpOKHeaders(httpExchange, headerInfo); if (!headRequest) { sendBody(httpExchange, resource.getBytes()); } } private static String getContentLength(final Resource requestedResource) { return Integer.toString(requestedResource.getBytes().length); } public static Resource getResource(final HttpExchange httpExchange, final File requestedFile) { if (requestedFile.isDirectory()) { final String pathVariable = getPathVariable(httpExchange); return new DirectoryResource(requestedFile, pathVariable); } return new FileResource(requestedFile); } public static void sendHttpOKHeaders(final HttpExchange httpExchange, final Map<String, String> headers) { final Headers responseHeaders = httpExchange.getResponseHeaders(); for (final Map.Entry<String, String> header : headers.entrySet()) { responseHeaders.set(header.getKey(), header.getValue()); } sendResponseHeaders(httpExchange, HTTP_OK); } public static void responseWith405(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, Statics.HTTP_NOT_ALLOWED); if (!headRequest) { sendBody(httpExchange, "405 - Not Allowed.".getBytes()); } } public static void responseWith501(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, HTTP_NOT_IMPLEMENTED); if (!headRequest) { sendBody(httpExchange, "501 - Not Implemented.".getBytes()); } } public static void responseWith400(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, HTTP_BAD_REQUEST); if (!headRequest) { sendBody(httpExchange, "400 - Bad Request.".getBytes()); } } public static void responseWith304(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, HTTP_NOT_MODIFIED); if (!headRequest) { sendBody(httpExchange, "304 - Not Modified.".getBytes()); } } public static void responseWith412(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, HTTP_PRECONDITION_FAILED); if (!headRequest) { sendBody(httpExchange, "412 - Precondition failed.".getBytes()); } } public static void responseWith404(final HttpExchange httpExchange, final boolean headRequest) { Headers responseHeaders = httpExchange.getResponseHeaders(); responseHeaders.set(HTTP_CONTENT_TYPE, HTTP_MIME_TEXT_PLAIN); sendResponseHeaders(httpExchange, HTTP_NOT_FOUND); if (!headRequest) { sendBody(httpExchange, "404 - Not Found.".getBytes()); } } private static void sendResponseHeaders(final HttpExchange httpExchange, final int status) { try { httpExchange.sendResponseHeaders(status, 0); } catch (IOException e) { LOGGER.error(e); } } public static void sendBody(final HttpExchange httpExchange, final byte[] content) { writeToStream(httpExchange.getResponseBody(), content); } private static void writeToStream(final OutputStream outputStream, final byte[] content) { try { outputStream.write(content); outputStream.flush(); } catch (IOException e) { LOGGER.error(e); } finally { try { if (outputStream != null) { outputStream.close(); } } catch (IOException e) { LOGGER.error(e); } } } public static File getFileResource(final HttpExchange httpExchange, final File baseDir) { String requestedUri = HttpUtils.getPathVariable(httpExchange); return baseDir.toPath().resolve(requestedUri.substring(1)).toFile(); } public static void parseGetParameters(HttpExchange exchange) throws UnsupportedEncodingException { final URI requestedUri = exchange.getRequestURI(); final String query = requestedUri.getRawQuery(); parseQuery(query, exchange); } public static void parsePostParameters(HttpExchange exchange) throws IOException { @SuppressWarnings("unchecked") final InputStreamReader isr = new InputStreamReader(exchange.getRequestBody(), UTF_8); final BufferedReader reader = new BufferedReader(isr); final String query = reader.readLine(); parseQuery(query, exchange); } private static void parseQuery(String query, HttpExchange exchange) throws UnsupportedEncodingException { if (query != null) { String pairs[] = query.split("&"); for (String pair : pairs) { String param[] = pair.split("="); String key = null; String value = null; if (param.length > 0) { key = URLDecoder.decode(param[0], Statics.UTF_8); } if (param.length > 1) { value = URLDecoder.decode(param[1], Statics.UTF_8); } exchange.setAttribute(key, value); } } } }