All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rapidoid.http.HttpUtils Maven / Gradle / Ivy

package org.rapidoid.http;

import org.rapidoid.RapidoidThing;
import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.commons.Str;
import org.rapidoid.config.BasicConfig;
import org.rapidoid.config.Conf;
import org.rapidoid.config.Config;
import org.rapidoid.crypto.Crypto;
import org.rapidoid.ctx.Ctxs;
import org.rapidoid.ctx.UserInfo;
import org.rapidoid.gui.reqinfo.ReqInfo;
import org.rapidoid.http.customize.Customization;
import org.rapidoid.http.customize.JsonResponseRenderer;
import org.rapidoid.http.impl.PathPattern;
import org.rapidoid.io.Res;
import org.rapidoid.lambda.Mapper;
import org.rapidoid.serialize.Serialize;
import org.rapidoid.u.U;
import org.rapidoid.util.ErrCodeAndMsg;
import org.rapidoid.util.Msc;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.Serializable;
import java.nio.BufferOverflowException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.regex.Pattern;

/*
 * #%L
 * rapidoid-http-fast
 * %%
 * Copyright (C) 2014 - 2016 Nikolche Mihajlovski and contributors
 * %%
 * 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.
 * #L%
 */

@Authors("Nikolche Mihajlovski")
@Since("5.0.0")
public class HttpUtils extends RapidoidThing implements HttpMetadata {

	private static final String PAGE_RELOAD = "

 Reloading...

"; private static final byte[] EMPTY_RESPONSE = {}; public static volatile Pattern REGEX_VALID_HTTP_RESOURCE = Pattern.compile("(?:/[A-Za-z0-9_\\-\\.]+)*/?"); public static final String _USER = "_user"; public static final String _EXPIRES = "_expires"; private static final Mapper PATH_PARAM_EXTRACTOR = new Mapper() { @Override public String map(String[] src) throws Exception { return src[1].split(":", 2)[0]; } }; @SuppressWarnings("unchecked") public static Map initAndDeserializeToken(Req req) { String token = req.cookie(TOKEN, null); if (U.isEmpty(token)) { token = req.data(TOKEN, null); } if (!U.isEmpty(token)) { byte[] decoded = Str.fromBase64(token.replace('$', '+').replace('_', '/')); byte[] tokenDecrypted = Crypto.decrypt(decoded); return (Map) Serialize.deserialize(tokenDecrypted); } else { return null; } } public static void saveTokenBeforeRenderingHeaders(Req req, Map tokenData) { String token = token(tokenData); setResponseTokenCookie(req.response(), token); } public static String token(Map token) { if (U.notEmpty(token)) { byte[] tokenBytes = serializeToken(token); byte[] tokenEncrypted = Crypto.encrypt(tokenBytes); return Str.toBase64(tokenEncrypted).replace('+', '$').replace('/', '_'); } else { return ""; } } private static byte[] serializeToken(Map token) { byte[] dest = new byte[2500]; try { int size = Serialize.serialize(dest, token); dest = Arrays.copyOf(dest, size); } catch (BufferOverflowException e) { throw U.rte("The token is too big!"); } return dest; } public static boolean isGetReq(Req req) { return req.verb().equalsIgnoreCase(GET); } public static boolean isPostReq(Req req) { return req.verb().equalsIgnoreCase(POST); } public static String resName(Req req) { return req.route() != null ? resNameFromRoutePath(req.route().path()) : resName(req.path()); } public static String resNameFromRoutePath(String path) { path = Str.replace(path, PathPattern.PATH_PARAM_REGEX, PATH_PARAM_EXTRACTOR); return resName(path); } public static String resName(String path) { if (U.notEmpty(path) && REGEX_VALID_HTTP_RESOURCE.matcher(path).matches() && !path.contains("..")) { String res = Str.triml(path, "/"); return res.isEmpty() ? "index" : Str.trimr(res, ".html"); } else { return null; } } public static boolean hasExtension(String name) { int pos = name.lastIndexOf('.'); return pos > 0 && pos < name.length() - 1; } public static void setContentTypeForFile(Resp resp, File file) { U.must(file.exists()); setContentType(resp, MediaType.getByFileName(file.getAbsolutePath())); } public static void setContentTypeForResource(Resp resp, Res resource) { U.must(resource.exists()); setContentType(resp, MediaType.getByFileName(resource.getName())); } public static void setContentType(Resp resp, MediaType mediaType) { resp.contentType(mediaType); } public static Res staticPage(Req req, String... possibleLocations) { String resName = resName(req); if (resName == null) return null; if (hasExtension(resName)) { return Res.from(resName, possibleLocations); } else { Res res = Res.from(resName, possibleLocations); if (!res.exists()) { res = Res.from(resName + ".html", possibleLocations); } return res; } } public static ErrCodeAndMsg getErrorCodeAndMsg(Throwable err) { Throwable cause = Msc.rootCause(err); int code; String defaultMsg; String msg = cause.getMessage(); if (cause instanceof SecurityException) { code = 403; defaultMsg = "Access Denied!"; } else if (cause instanceof NotFound) { code = 404; defaultMsg = "The requested resource could not be found!"; } else if (Msc.isValidationError(cause)) { code = 422; defaultMsg = "Validation Error!"; if (cause.getClass().getName().equals("javax.validation.ConstraintViolationException")) { Set> violations = ((ConstraintViolationException) cause).getConstraintViolations(); StringBuilder sb = new StringBuilder(); sb.append("Validation failed: "); for (Iterator> it = U.safe(violations).iterator(); it.hasNext(); ) { ConstraintViolation v = it.next(); sb.append(v.getRootBeanClass().getSimpleName()); sb.append("."); sb.append(v.getPropertyPath()); sb.append(" ("); sb.append(v.getMessage()); sb.append(")"); if (it.hasNext()) { sb.append(", "); } } msg = sb.toString(); } } else { code = 500; defaultMsg = "Internal Server Error!"; } msg = U.or(msg, defaultMsg); return new ErrCodeAndMsg(code, msg); } public static String getErrorMessageAndSetCode(Resp resp, Throwable err) { ErrCodeAndMsg codeAndMsg = getErrorCodeAndMsg(err); resp.code(codeAndMsg.code()); return codeAndMsg.msg(); } public static Map getErrorInfo(Resp resp, Throwable error) { String errorMessage = getErrorMessageAndSetCode(resp, error); return U.map("error", errorMessage, "code", resp.code(), "status", HttpResponseCodes.status(resp.code())); } public static void postProcessResponse(Resp resp) { postProcessRedirect(resp); postProcessFile(resp); postProcessFilename(resp); } private static void postProcessFile(Resp resp) { File file = resp.file(); if (file != null) { U.must(file.exists()); if (resp.filename() == null) { resp.filename(); } setContentTypeForFile(resp, file); resp.result(Res.from(file).getBytes()); } } private static void postProcessFilename(Resp resp) { String filename = resp.filename(); if (filename != null) { resp.headers().put(HttpHeaders.CONTENT_DISPOSITION.name(), "attachment; filename=\"" + filename + "\""); resp.headers().put(HttpHeaders.CACHE_CONTROL.name(), "private"); } } private static void postProcessRedirect(Resp resp) { String redirect = resp.redirect(); if (redirect != null) { if (resp.code() < 300 || resp.code() >= 400) { resp.code(303); } resp.headers().put(HttpHeaders.LOCATION.name(), redirect); if (resp.result() == null && resp.body() == null) { resp.body(EMPTY_RESPONSE); } } } public static void reload(Req x) { Map sel = U.map("body", PAGE_RELOAD); x.response().json(U.map("_sel_", sel)); } public static String constructUrl(Req x, String path) { return (Conf.ROOT.is("https") ? "https://" : "http://") + x.host() + path; } public static byte[] responseToBytes(Req req, Object result, MediaType contentType, JsonResponseRenderer jsonRenderer) { if (U.eq(contentType, MediaType.JSON)) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { jsonRenderer.renderJson(req, result, out); } catch (Exception e) { throw U.rte(e); } return out.toByteArray(); } else { return Msc.toBytes(result); } } public static void resultToResponse(Req req, Object result) { if (result instanceof Req) { if (req != result) { req.response().result("Unknown request instance was received as result!"); } } else if (result instanceof Resp) { if (req.response() != result) { req.response().result("Unknown response instance was received as result!"); } } else { req.response().result(result); } } public static String getContextPath(Req req) { return zone(req).entry("contextPath").or(""); } public static BasicConfig zone(Customization custom, String zone) { Config appConfig = custom.config().sub("app"); if (zone != null) { String zoneKey = zone + "-zone"; return custom.config().sub(zoneKey).or(appConfig); } else { return appConfig; } } public static BasicConfig zone(Req req) { Customization custom = Customization.of(req); return zone(custom, req.zone()); } @SuppressWarnings("unchecked") public static Object postprocessResult(Req req, Object result) throws Exception { if (result instanceof Req || result instanceof Resp || result instanceof HttpStatus) { return result; } else if (result == null) { return null; // not found } else if ((result instanceof Future) || (result instanceof org.rapidoid.concurrent.Future)) { return req.async(); } else { return result; } } public static void setResponseTokenCookie(Resp resp, String token) { resp.cookie(TOKEN, token, "HttpOnly"); } public static String cookiePath() { String ctxPath = ReqInfo.get().contextPath(); return U.notEmpty(ctxPath) ? ctxPath : "/"; } public static void clearUserData(Req req) { if (Ctxs.hasContext()) { Ctxs.required().setUser(UserInfo.ANONYMOUS); } if (req.hasToken()) { Map token = req.token(); token.remove(_USER); token.remove(_EXPIRES); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy