/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.commons.lang; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.*; /** A collection of utilities for encoding URLs. */ public class URLEncodedUtils { private static final String PARAMETER_SEPARATOR = "&"; private static final String NAME_VALUE_SEPARATOR = "="; /** * Returns Map<String, Set<String>> as built from the * URI's query portion. For example, a URI of http://example.org/path/to/file?a=1&b=2&c=3&c=4 * would return a Map three key is a name name of parameter Set<String> * is a values, a={1}, one for b={2} and two for c={3,4}. * <p/> * <p/> * This is typically useful while parsing an HTTP PUT. * * @param uri * uri to parse * @param encoding * encoding to use while parsing the query. */ public static Map<String, Set<String>> parse(final URI uri, final String encoding) { Map<String, Set<String>> result = Collections.emptyMap(); final String query = uri.getRawQuery(); if (query != null && query.length() > 0) { result = new HashMap<>(); parse(result, new Scanner(query), encoding, true); } return result; } /** * Returns Map<String, Set<String>> as built from the * URI's query portion. Parameters encoding does not performed. * For example, a URI of http://example.org/path/to/file?a=1&b=2&c=3&c=4 * would return a Map three key is a name name of parameter Set<String> * is a values, a={1}, one for b={2} and two for c={3,4}. * <p/> * <p/> * This is typically useful while parsing an HTTP PUT. * * @param uri * uri to parse */ public static Map<String, Set<String>> parse(final URI uri) { return parse(uri, true); } /** * Returns Map<String, Set<String>> as built from the * URI's query portion. Parameters encoding does not performed. * For example, a URI of http://example.org/path/to/file?a=1&b=2&c=3&c=4 * would return a Map three key is a name name of parameter Set<String> * is a values, a={1}, one for b={2} and two for c={3,4}. * <p/> * <p/> * This is typically useful while parsing an HTTP PUT. * * @param uri * uri to parse * @param decodeQueryParam * decode query parameter or not. */ public static Map<String, Set<String>> parse(final URI uri, boolean decodeQueryParam) { Map<String, Set<String>> result = Collections.emptyMap(); final String query = uri.getRawQuery(); if (query != null && query.length() > 0) { result = new HashMap<>(); parse(result, new Scanner(query), null, decodeQueryParam); } return result; } /** * Adds all parameters within the Scanner to the list of * <code>parameters</code>, as encoded by <code>encoding</code>. * If <code>encoding</code> is null encoding does not performed. * For example, a scanner containing the string <code>a=1&b=2&c=3</code> would * add the Map<String, Set<String>> a=1, b=2, and c=3 to the * list of parameters. * * @param parameters * List to add parameters to. * @param scanner * Input that contains the parameters to parse. * @param encoding * Encoding to use when decoding the parameters. If encoding is null encoding does not performed. */ private static void parse(final Map<String, Set<String>> parameters, final Scanner scanner, final String encoding, boolean decodeQueryParam) { scanner.useDelimiter(PARAMETER_SEPARATOR); while (scanner.hasNext()) { final String[] nameValue = scanner.next().split(NAME_VALUE_SEPARATOR); if (nameValue.length == 0 || nameValue.length > 2) throw new IllegalArgumentException("bad parameter"); final String name = decodeQueryParam ? decode(nameValue[0], encoding) : nameValue[0]; String value = null; if (nameValue.length == 2) value = decodeQueryParam ? decode(nameValue[1], encoding) : nameValue[1]; Set<String> values = parameters.get(name); if (values == null) { values = new LinkedHashSet<>(); parameters.put(name, values); } if (value != null) { values.add(value); } } } /** * Returns a String that is suitable for use as an <code>application/x-www-form-urlencoded</code> * list of parameters in an HTTP PUT or HTTP POST. * * @param parameters * The parameters to include. * @param encoding * The encoding to use. */ public static String format(final Map<String, Set<String>> parameters, final String encoding) { final StringBuilder result = new StringBuilder(); for (Map.Entry<String, Set<String>> parameter : parameters.entrySet()) { final String encodedName = encode(parameter.getKey(), encoding); final Set<String> values = parameter.getValue(); if (values == null || values.size() == 0) { result.append(encodedName); result.append(NAME_VALUE_SEPARATOR); result.append(""); } else { for (String value : values) { final String encodedValue = value != null ? encode(value, encoding) : ""; if (result.length() > 0) result.append(PARAMETER_SEPARATOR); result.append(encodedName); result.append(NAME_VALUE_SEPARATOR); result.append(encodedValue); } } } return result.toString(); } private static String decode(final String content, final String encoding) { try { return URLDecoder.decode(content, encoding != null ? encoding : "UTF-8"); } catch (UnsupportedEncodingException problem) { throw new IllegalArgumentException(problem); } } private static String encode(final String content, final String encoding) { try { return URLEncoder.encode(content, encoding != null ? encoding : "UTF-8"); } catch (UnsupportedEncodingException problem) { throw new IllegalArgumentException(problem); } } }