1 /******************************************************************************* 2 * Copyright (c) 2003, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.ui.internal.intro.impl.model.url; 15 16 import java.io.ByteArrayOutputStream; 17 import java.net.MalformedURLException; 18 import java.net.URL; 19 import java.nio.charset.StandardCharsets; 20 import java.util.Properties; 21 22 import org.eclipse.ui.internal.intro.impl.util.Log; 23 24 /** 25 * A parser that knows how to parser OOBE action URLs. If URL is a valid intro 26 * url, it will create an instance of the IntroURL class. 27 */ 28 public class IntroURLParser { 29 30 // private String url_string = null; 31 private boolean hasProtocol = false; 32 private boolean isIntroUrl = false; 33 34 private URL url_inst; 35 36 /** 37 * Constructor that gets the URL to parse. 38 */ IntroURLParser(String url)39 public IntroURLParser(String url) { 40 // create a URL instance, and parser it for parameters. 41 parseUrl(url); 42 } 43 parseUrl(String url)44 private void parseUrl(String url) { 45 if (url == null) 46 return; 47 url_inst = null; 48 try { 49 url_inst = new URL(url); 50 } catch (MalformedURLException e) { 51 // not a valid URL. set state. 52 return; 53 } 54 55 if (url_inst.getProtocol() != null) { 56 // URL has some valid protocol. Check to see if it is an intro url. 57 hasProtocol = true; 58 isIntroUrl = isIntroUrl(url_inst); 59 return; 60 } 61 62 // not an Intro URL. do nothing. 63 return; 64 } 65 66 67 /** 68 * @return Returns the hasProtocol. 69 */ hasProtocol()70 public boolean hasProtocol() { 71 return hasProtocol; 72 } 73 74 /** 75 * @return Returns the isIntroUrl. 76 */ hasIntroUrl()77 public boolean hasIntroUrl() { 78 return isIntroUrl; 79 } 80 81 82 /** 83 * @return Returns the currebt url Protocol. 84 */ getProtocol()85 public String getProtocol() { 86 return url_inst.getProtocol(); 87 } 88 89 90 /** 91 * @return Returns the currebt url Protocol. 92 */ getHost()93 public String getHost() { 94 return url_inst.getHost(); 95 } 96 97 98 /** 99 * Checks to see if tha passed URL is an Intro URL. An intro URL is an http 100 * URL that has the intro plugin id as a host. eg: 101 * "http://org.eclipse.ui.intro/test". 102 * 103 * @param url 104 * @return true if url is an intro URL. 105 */ isIntroUrl(URL url)106 private boolean isIntroUrl(URL url) { 107 if (!url.getProtocol().equalsIgnoreCase(IntroURL.INTRO_PROTOCOL)) 108 // quick exit. If it is not http, url is not an Intro url. 109 return false; 110 111 if (url.getHost().equalsIgnoreCase(IntroURL.INTRO_HOST_ID)) 112 return true; 113 114 return false; 115 } 116 117 118 119 /** 120 * @return Returns the introURL. Will be null if the parsed URL is not an 121 * Intro URL. 122 */ getIntroURL()123 public IntroURL getIntroURL() { 124 IntroURL introURL = null; 125 if (isIntroUrl) { 126 // valid intro URL. Extract the action and parameters. 127 String action = getPathAsAction(url_inst); 128 Properties parameters = getQueryParameters(url_inst); 129 130 // class instance vars are already populated by now. 131 introURL = new IntroURL(action, parameters); 132 } 133 return introURL; 134 } 135 136 137 138 /** 139 * Retruns the path attribute of the passed URL, stripped out of the leading 140 * "/". Returns null if the url does not have a path. 141 * 142 * @param url 143 * @return 144 */ getPathAsAction(URL url)145 private String getPathAsAction(URL url) { 146 // get possible action. 147 String action = url.getPath(); 148 // remove leading "/" from path. 149 if (action != null) 150 action = action.substring(1); 151 return action; 152 } 153 154 /** 155 * Retruns the Query part of the URL as an instance of a Properties class. 156 * 157 * @param url 158 * @return 159 */ getQueryParameters(URL url)160 public Properties getQueryParameters(URL url) { 161 // parser all query parameters. 162 Properties properties = new Properties(); 163 String query = url.getQuery(); 164 if (query == null) 165 // we do not have any parameters in this URL, return an empty 166 // Properties instance. 167 return properties; 168 169 // now extract the key/value pairs from the query. 170 String[] params = query.split("&"); //$NON-NLS-1$ 171 for (int i = 0; i < params.length; i++) { 172 // for every parameter, ie: key=value pair, create a property 173 // entry. we know we have the key as the first string in the array, 174 // and the value as the second array. 175 String[] keyValuePair = params[i].split("="); //$NON-NLS-1$ 176 if (keyValuePair.length != 2) { 177 Log.warning("Ignoring the following Intro URL parameter: " //$NON-NLS-1$ 178 + params[i]); 179 continue; 180 } 181 182 String key = urlDecode(keyValuePair[0]); 183 if (key == null) { 184 Log.warning("Failed to URL decode key: " + keyValuePair[0]); //$NON-NLS-1$ 185 continue; 186 } 187 188 String value = urlDecode(keyValuePair[1]); 189 if (value == null) { 190 Log.warning("Failed to URL decode value: " + keyValuePair[1]); //$NON-NLS-1$ 191 continue; 192 } 193 194 properties.setProperty(key, value); 195 } 196 return properties; 197 } 198 199 200 /* 201 * Note: This was copied and adapted from org.eclipse.help.internal.util.URLCoder 202 */ urlDecode(String encodedURL)203 private static String urlDecode(String encodedURL) { 204 int len = encodedURL.length(); 205 ByteArrayOutputStream os = new ByteArrayOutputStream(len); 206 207 for (int i = 0; i < len;) { 208 switch (encodedURL.charAt(i)) { 209 case '%': 210 if (len >= i + 3) { 211 os.write(Integer.parseInt(encodedURL.substring(i + 1, i + 3), 16)); 212 } 213 i += 3; 214 break; 215 case '+': // exception from standard 216 os.write(' '); 217 i++; 218 break; 219 default: 220 os.write(encodedURL.charAt(i++)); 221 break; 222 } 223 } 224 return new String(os.toByteArray(), StandardCharsets.UTF_8); 225 } 226 227 } 228