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