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             * &amp;client_id=s6BhdRkqt3
065             * &amp;state=xyz
066             * &amp;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             * &amp;client_id=s6BhdRkqt3
127             * &amp;state=xyz
128             * &amp;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    }