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