001 package com.nimbusds.oauth2.sdk.util; 002 003 004 import java.io.UnsupportedEncodingException; 005 import java.net.MalformedURLException; 006 import java.net.URL; 007 import java.net.URLDecoder; 008 import java.net.URLEncoder; 009 import java.util.HashMap; 010 import java.util.Iterator; 011 import java.util.Map; 012 013 014 /** 015 * URL operations. 016 * 017 * @author Vladimir Dzhuvinov 018 */ 019 public class URLUtils { 020 021 022 /** 023 * The default UTF-8 character set. 024 */ 025 public static final String CHARSET = "utf-8"; 026 027 028 /** 029 * Gets the base part (protocol, host, port and path) of the specified 030 * URL. 031 * 032 * @param url The URL. May be {@code null}. 033 * 034 * @return The base part of the URL, {@code null} if the original URL 035 * is {@code null} or doesn't specify a protocol. 036 */ 037 public static URL getBaseURL(final URL url) { 038 039 if (url == null) 040 return null; 041 042 try { 043 return new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getPath()); 044 045 } catch (MalformedURLException e) { 046 047 return null; 048 } 049 } 050 051 052 /** 053 * Serialises the specified map of parameters into a URL query string. 054 * The parameter keys and values are 055 * {@code application/x-www-form-urlencoded} encoded. 056 * 057 * <p>Note that the '?' character preceding the query string in GET 058 * requests is not included in the returned string. 059 * 060 * <p>Example query string: 061 * 062 * <pre> 063 * response_type=code 064 * &client_id=s6BhdRkqt3 065 * &state=xyz 066 * &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 067 * </pre> 068 * 069 * <p>The opposite method is {@link #parseParameters}. 070 * 071 * @param params A map of the URL query parameters. May be empty or 072 * {@code null}. 073 * 074 * @return The serialised URL query string, empty if no parameters. 075 */ 076 public static String serializeParameters(final Map<String,String> params) { 077 078 if (params == null || params.isEmpty()) 079 return ""; 080 081 StringBuilder sb = new StringBuilder(); 082 083 Iterator <Map.Entry<String,String>> it = params.entrySet().iterator(); 084 085 while (it.hasNext()) { 086 087 Map.Entry<String,String> entry = it.next(); 088 089 if (entry.getKey() == null || entry.getValue() == null) 090 continue; 091 092 try { 093 String encodedKey = URLEncoder.encode(entry.getKey(), CHARSET); 094 String encodedValue = URLEncoder.encode(entry.getValue(), CHARSET); 095 096 if (sb.length() > 0) 097 sb.append('&'); 098 099 sb.append(encodedKey); 100 sb.append('='); 101 sb.append(encodedValue); 102 103 } catch (UnsupportedEncodingException e) { 104 105 // UTF-8 should always be supported 106 } 107 } 108 109 return sb.toString(); 110 } 111 112 113 /** 114 * Parses the specified URL query string into a parameter map. If a 115 * parameter has multiple values only the first one will be saved. The 116 * parameter keys and values are 117 * {@code application/x-www-form-urlencoded} decoded. 118 * 119 * <p>Note that the '?' character preceding the query string in GET 120 * requests must not be included. 121 * 122 * <p>Example query string: 123 * 124 * <pre> 125 * response_type=code 126 * &client_id=s6BhdRkqt3 127 * &state=xyz 128 * &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 129 * </pre> 130 * 131 * <p>The opposite method {@link #serializeParameters}. 132 * 133 * @param query The URL query string to parse. May be {@code null}. 134 * 135 * @return A map of the URL query parameters, empty if none are found. 136 */ 137 public static Map<String,String> parseParameters(final String query) { 138 139 Map<String,String> params = new HashMap<String, String>(); 140 141 if (query == null) 142 return params; // empty map 143 144 try { 145 for (String param : query.split("&")) { 146 147 String pair[] = param.split("="); 148 149 String key = URLDecoder.decode(pair[0], CHARSET); 150 151 // Save the first value only 152 if (params.containsKey(key)) 153 continue; 154 155 String value = ""; 156 157 if (pair.length > 1) 158 value = URLDecoder.decode(pair[1], CHARSET); 159 160 params.put(key, value); 161 } 162 163 } catch (UnsupportedEncodingException e) { 164 165 // UTF-8 should always be supported 166 } 167 168 return params; 169 } 170 171 172 /** 173 * Prevents instantiation. 174 */ 175 private URLUtils() { 176 177 // do nothing 178 } 179 }