/* * JBoss, Home of Professional Open Source. * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 io.undertow.util; import io.undertow.server.HttpServerExchange; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Deque; import java.util.Map; /** * Utility class for building redirects. * * @author Stuart Douglas */ public class RedirectBuilder { public static final String UTF_8 = StandardCharsets.UTF_8.name(); /** * Redirects to a new relative path. All other data from the exchange is preserved. * * @param exchange The HTTP server exchange * @param newRelativePath The new relative path * @return */ public static String redirect(final HttpServerExchange exchange, final String newRelativePath) { return redirect(exchange, newRelativePath, true); } /** * Redirects to a new relative path. All other data from the exchange is preserved. * * @param exchange The HTTP server exchange * @param newRelativePath The new relative path * @param includeParameters If query and path parameters from the exchange should be included * @return */ public static String redirect(final HttpServerExchange exchange, final String newRelativePath, final boolean includeParameters) { try { StringBuilder uri = new StringBuilder(exchange.getRequestScheme()); uri.append("://"); uri.append(exchange.getHostAndPort()); uri.append(encodeUrlPart(exchange.getResolvedPath())); if (exchange.getResolvedPath().endsWith("/")) { if (newRelativePath.startsWith("/")) { uri.append(encodeUrlPart(newRelativePath.substring(1))); } else { uri.append(encodeUrlPart(newRelativePath)); } } else { if (!newRelativePath.startsWith("/")) { uri.append('/'); } uri.append(encodeUrlPart(newRelativePath)); } if (includeParameters) { if (!exchange.getPathParameters().isEmpty()) { boolean first = true; uri.append(';'); for (Map.Entry<String, Deque<String>> param : exchange.getPathParameters().entrySet()) { for (String value : param.getValue()) { if (first) { first = false; } else { uri.append('&'); } uri.append(URLEncoder.encode(param.getKey(), UTF_8)); uri.append('='); uri.append(URLEncoder.encode(value, UTF_8)); } } } if (!exchange.getQueryString().isEmpty()) { uri.append('?'); uri.append(exchange.getQueryString()); } } return uri.toString(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } /** * perform URL encoding * <p/> * TODO: this whole thing is kinda crappy. * * @return */ private static String encodeUrlPart(final String part) throws UnsupportedEncodingException { //we need to go through and check part by part that a section does not need encoding int pos = 0; for (int i = 0; i < part.length(); ++i) { char c = part.charAt(i); if(c == '?') { break; } else if (c == '/') { if (pos != i) { String original = part.substring(pos, i); String encoded = URLEncoder.encode(original, UTF_8); if (!encoded.equals(original)) { return realEncode(part, pos); } } pos = i + 1; } else if (c == ' ') { return realEncode(part, pos); } } return part; } private static String realEncode(String part, int startPos) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); sb.append(part.substring(0, startPos)); int pos = startPos; for (int i = startPos; i < part.length(); ++i) { char c = part.charAt(i); if(c == '?') { break; } else if (c == '/') { if (pos != i) { String original = part.substring(pos, i); String encoded = URLEncoder.encode(original, UTF_8); sb.append(encoded); sb.append('/'); pos = i + 1; } } } String original = part.substring(pos); String encoded = URLEncoder.encode(original, UTF_8); sb.append(encoded); return sb.toString(); } private RedirectBuilder() { } }