Ticket #24907: api-strip-slash.patch
| File api-strip-slash.patch, 17.5 KB (added by , 2 days ago) |
|---|
-
src/org/openstreetmap/josm/data/oauth/OAuthParameters.java
diff --git src/org/openstreetmap/josm/data/oauth/OAuthParameters.java src/org/openstreetmap/josm/data/oauth/OAuthParameters.java index 73ed6ce10c..f4905c04c1 100644
public final class OAuthParameters { 147 147 final String clientSecret; 148 148 final String redirectUri = "http://127.0.0.1:8111/oauth_authorization"; 149 149 final String baseUrl; 150 apiUrl = apiUrl == null ? OsmApi.getOsmApi().getServerUrl() : apiUrl;150 apiUrl = OsmApi.normalizeApiUrl(apiUrl == null ? OsmApi.getOsmApi().getServerUrl() : apiUrl); 151 151 switch (apiUrl) { 152 152 case OSM_API_DEV: 153 153 case OSM_API_MASTER: … … public final class OAuthParameters { 238 238 * @since 18650 239 239 */ 240 240 public static IOAuthParameters createFromApiUrl(String apiUrl, OAuthVersion oAuthVersion) { 241 apiUrl = OsmApi.normalizeApiUrl(apiUrl); 241 242 final String originalApiUrl = apiUrl; 242 243 // We actually need the host 243 244 if (apiUrl.startsWith("https://") || apiUrl.startsWith("http://")) { -
src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java
diff --git src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java index 86fe3d9a31..ba6938d5c4 100644
import org.openstreetmap.josm.data.osm.UserInfo; 18 18 import org.openstreetmap.josm.gui.HelpAwareOptionPane; 19 19 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 20 20 import org.openstreetmap.josm.gui.help.HelpUtil; 21 import org.openstreetmap.josm.io.OsmApi; 21 22 import org.openstreetmap.josm.io.OsmApiException; 22 23 import org.openstreetmap.josm.io.OsmServerUserInfoReader; 23 24 import org.openstreetmap.josm.io.OsmTransferException; … … public class TestAccessTokenTask extends PleaseWaitRunnable { 59 60 CheckParameterUtil.ensureParameterNotNull(accessToken, "accessToken"); 60 61 this.tokenOAuth2 = accessToken; 61 62 this.parent = parent; 62 this.apiUrl = apiUrl;63 this.apiUrl = OsmApi.normalizeApiUrl(apiUrl); 63 64 } 64 65 65 66 @Override … … public class TestAccessTokenTask extends PleaseWaitRunnable { 81 82 this.tokenOAuth2.sign(con); 82 83 } 83 84 84 protected String normalizeApiUrl(String url) {85 // remove leading and trailing white space86 url = url.trim();87 88 // remove trailing slashes89 while (url.endsWith("/")) {90 url = url.substring(0, url.lastIndexOf('/'));91 }92 return url;93 }94 95 85 protected UserInfo getUserDetails() throws OsmOAuthAuthorizationException, XmlParsingException, OsmTransferException { 96 86 boolean authenticatorEnabled = true; 97 87 try { 98 URL url = new URL( normalizeApiUrl(apiUrl)+ "/0.6/user/details");88 URL url = new URL(apiUrl + "/0.6/user/details"); 99 89 authenticatorEnabled = DefaultAuthenticator.getInstance().isEnabled(); 100 90 DefaultAuthenticator.getInstance().setEnabled(false); 101 91 -
src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java
diff --git src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java src/org/openstreetmap/josm/gui/preferences/server/ApiUrlTestTask.java index ad84e7e2f8..9681092738 100644
import org.openstreetmap.josm.gui.HelpAwareOptionPane; 16 16 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 17 17 import org.openstreetmap.josm.gui.help.HelpUtil; 18 18 import org.openstreetmap.josm.io.Capabilities; 19 import org.openstreetmap.josm.io.OsmApi; 19 20 import org.openstreetmap.josm.io.OsmTransferException; 20 21 import org.openstreetmap.josm.tools.CheckParameterUtil; 21 22 import org.openstreetmap.josm.tools.HttpClient; … … public class ApiUrlTestTask extends PleaseWaitRunnable { 48 49 super(parent, tr("Testing OSM API URL ''{0}''", url), false /* don't ignore exceptions */); 49 50 CheckParameterUtil.ensureParameterNotNull(url, "url"); 50 51 this.parent = parent; 51 this.url = url;52 this.url = OsmApi.normalizeApiUrl(url); 52 53 } 53 54 54 55 protected void alertInvalidUrl(String url) { … … public class ApiUrlTestTask extends PleaseWaitRunnable { 66 67 ); 67 68 } 68 69 69 protected void alertInvalidCapabilitiesUrl(String url) {70 protected void alertInvalidCapabilitiesUrl(String capabilitiesUrl) { 70 71 HelpAwareOptionPane.showMessageDialogInEDT( 71 72 parent, 72 73 tr("<html>" 73 74 + "Failed to build URL ''{0}'' for validating the OSM API server.<br>" 74 75 + "Please check the spelling of ''{1}'' and validate again." 75 76 +"</html>", 76 url,77 getNormalizedApiUrl()77 capabilitiesUrl, 78 url 78 79 ), 79 80 tr("Invalid API URL"), 80 81 JOptionPane.ERROR_MESSAGE, … … public class ApiUrlTestTask extends PleaseWaitRunnable { 90 91 + "Please check the spelling of ''{1}'' and your Internet connection and validate again." 91 92 +"</html>", 92 93 url, 93 getNormalizedApiUrl()94 url 94 95 ), 95 96 tr("Connection to API failed"), 96 97 JOptionPane.ERROR_MESSAGE, … … public class ApiUrlTestTask extends PleaseWaitRunnable { 107 108 + "Please check the spelling of ''{1}'' and validate again." 108 109 + "</html>", 109 110 retCode, 110 getNormalizedApiUrl()111 url 111 112 ), 112 113 tr("Connection to API failed"), 113 114 JOptionPane.ERROR_MESSAGE, … … public class ApiUrlTestTask extends PleaseWaitRunnable { 123 124 + "It is likely that ''{0}'' is not an OSM API server.<br>" 124 125 + "Please check the spelling of ''{0}'' and validate again." 125 126 + "</html>", 126 getNormalizedApiUrl()127 url 127 128 ), 128 129 tr("Connection to API failed"), 129 130 JOptionPane.ERROR_MESSAGE, … … public class ApiUrlTestTask extends PleaseWaitRunnable { 146 147 // Do nothing 147 148 } 148 149 149 /**150 * Removes leading and trailing whitespace from the API URL and removes trailing '/'.151 *152 * @return the normalized API URL153 */154 protected String getNormalizedApiUrl() {155 String apiUrl = url.trim();156 while (apiUrl.endsWith("/")) {157 apiUrl = apiUrl.substring(0, apiUrl.lastIndexOf('/'));158 }159 return apiUrl;160 }161 162 150 @Override 163 151 protected void realRun() throws SAXException, IOException, OsmTransferException { 164 152 try { 165 153 try { 166 new URL( getNormalizedApiUrl());154 new URL(url); 167 155 } catch (MalformedURLException e) { 168 alertInvalidUrl( getNormalizedApiUrl());156 alertInvalidUrl(url); 169 157 return; 170 158 } 171 159 URL capabilitiesUrl; 172 String getCapabilitiesUrl = getNormalizedApiUrl()+ "/0.6/capabilities";160 String getCapabilitiesUrl = url + "/0.6/capabilities"; 173 161 try { 174 162 capabilitiesUrl = new URL(getCapabilitiesUrl); 175 163 } catch (MalformedURLException e) { -
src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java
diff --git src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java src/org/openstreetmap/josm/gui/preferences/server/OsmApiUrlInputPanel.java index ca7f38d466..16a6a66184 100644
public class OsmApiUrlInputPanel extends JPanel { 125 125 */ 126 126 public void saveToPreferences() { 127 127 String oldUrl = OsmApi.getOsmApi().getServerUrl(); 128 String hmiUrl = get StrippedApiUrl();128 String hmiUrl = getApiUrl(); 129 129 if (cbUseDefaultServerUrl.isSelected() || Config.getUrls().getDefaultOsmApiUrl().equals(hmiUrl)) { 130 130 Config.getPref().put("osm-server.url", null); 131 131 } else { … … public class OsmApiUrlInputPanel extends JPanel { 146 146 } 147 147 148 148 /** 149 * Returns the entered API URL, stripped of leading and trailing white characters. 150 * @return the entered API URL, stripped of leading and trailing white characters. May be an empty string 151 * if nothing has been entered. In this case, it means the user wants to use {@link IUrls#getDefaultOsmApiUrl}. 152 * @see Utils#strip(String) 153 * @since 6602 149 * Returns the entered API URL, normalized with {@link OsmApi#normalizeApiUrl(String)}, that is stripped of 150 * leading and trailing white characters and of trailing '/'. 151 * @return the entered API URL. May be an empty string if nothing has been entered. In this case, it means 152 * the user wants to use {@link IUrls#getDefaultOsmApiUrl}. 153 * @see OsmApi#normalizeApiUrl(String) 154 * @since xxx (renamed from {@code getStrippedApiUrl}, which existed since 6602) 154 155 */ 155 public final String get StrippedApiUrl() {156 return Utils.strip(tfOsmServerUrl.getText());156 public final String getApiUrl() { 157 return OsmApi.normalizeApiUrl(tfOsmServerUrl.getText()); 157 158 } 158 159 159 160 class ValidateApiUrlAction extends AbstractAction implements DocumentListener { … … public class OsmApiUrlInputPanel extends JPanel { 167 168 168 169 @Override 169 170 public void actionPerformed(ActionEvent arg0) { 170 final String url = get StrippedApiUrl();171 final String url = getApiUrl(); 171 172 final ApiUrlTestTask task = new ApiUrlTestTask(OsmApiUrlInputPanel.this, url); 172 173 MainApplication.worker.submit(task); 173 174 Runnable r = () -> { … … public class OsmApiUrlInputPanel extends JPanel { 190 191 } 191 192 192 193 protected final void updateEnabledState() { 193 String url = get StrippedApiUrl();194 String url = getApiUrl(); 194 195 boolean enabled = !url.isEmpty() && !url.equals(lastTestedUrl); 195 196 if (enabled) { 196 197 lblValid.setIcon(null); … … public class OsmApiUrlInputPanel extends JPanel { 275 276 276 277 class ApiUrlPropagator extends FocusAdapter implements ActionListener { 277 278 protected void propagate() { 278 propagate(get StrippedApiUrl());279 propagate(getApiUrl()); 279 280 } 280 281 281 282 protected void propagate(String url) { -
src/org/openstreetmap/josm/io/OsmApi.java
diff --git src/org/openstreetmap/josm/io/OsmApi.java src/org/openstreetmap/josm/io/OsmApi.java index 8895b26e7b..69643ebb18 100644
public class OsmApi extends OsmConnection { 133 133 * 134 134 */ 135 135 public static OsmApi getOsmApi(String serverUrl) { 136 OsmApi api = instances.get(serverUrl); 136 String url = normalizeApiUrl(serverUrl); 137 OsmApi api = instances.get(url); 137 138 if (api == null) { 138 api = new OsmApi( serverUrl);139 api = new OsmApi(url); 139 140 cacheInstance(api); 140 141 } 141 142 return api; 142 143 } 143 144 145 /** 146 * Normalizes an OSM API URL: removes leading and trailing white space and any trailing {@code '/'}. 147 * <p> 148 * The URL may be entered with a trailing slash, but code which compares it to a known API URL or derives 149 * another URL from it does not expect one: OAuth would not find the client id of the server, and the links 150 * to the web site of the server (browse, history, user) would be built from the API path. 151 * @param serverUrl the server URL, may be null 152 * @return the normalized URL, or null if {@code serverUrl} is null 153 * @since xxx 154 */ 155 public static String normalizeApiUrl(String serverUrl) { 156 if (serverUrl == null) { 157 return null; 158 } 159 String url = Utils.strip(serverUrl); 160 while (url.endsWith("/") && !url.endsWith("://")) { 161 url = url.substring(0, url.length() - 1); 162 } 163 return url; 164 } 165 144 166 protected static void cacheInstance(OsmApi api) { 145 167 instances.put(api.getServerUrl(), api); 146 168 } … … public class OsmApi extends OsmConnection { 181 203 */ 182 204 protected OsmApi(String serverUrl) { 183 205 CheckParameterUtil.ensureParameterNotNull(serverUrl, "serverUrl"); 184 this.serverUrl = serverUrl;206 this.serverUrl = normalizeApiUrl(serverUrl); 185 207 } 186 208 187 209 /** -
test/unit/org/openstreetmap/josm/data/preferences/JosmUrlsTest.java
diff --git test/unit/org/openstreetmap/josm/data/preferences/JosmUrlsTest.java test/unit/org/openstreetmap/josm/data/preferences/JosmUrlsTest.java index cea11fd377..fce4aaae73 100644
class JosmUrlsTest { 19 19 void testGetBaseUserUrl() { 20 20 assertEquals("https://api06.dev.openstreetmap.org/user", Config.getUrls().getBaseUserUrl()); 21 21 } 22 23 /** 24 * An API URL entered with a trailing slash must give the same web site URLs as one without, so that 25 * "History (web)" and the other links to the server are built from the web site and not from the API path. 26 */ 27 @Test 28 void testApiUrlWithTrailingSlash() { 29 Config.getPref().put("osm-server.url", "https://api06.dev.openstreetmap.org/api/"); 30 assertEquals("https://api06.dev.openstreetmap.org", Config.getUrls().getOSMWebsiteDependingOnSelectedApi()); 31 assertEquals("https://api06.dev.openstreetmap.org", Config.getUrls().getBaseBrowseUrl()); 32 assertEquals("https://api06.dev.openstreetmap.org/user", Config.getUrls().getBaseUserUrl()); 33 } 34 35 /** 36 * The default API URL is recognized even when it is entered with a trailing slash, so the links point to 37 * the OSM web site rather than to the API host. 38 */ 39 @Test 40 void testDefaultApiUrlWithTrailingSlash() { 41 Config.getPref().put("osm-server.url", Config.getUrls().getDefaultOsmApiUrl() + '/'); 42 assertEquals(Config.getUrls().getOSMWebsite(), Config.getUrls().getOSMWebsiteDependingOnSelectedApi()); 43 } 22 44 } -
test/unit/org/openstreetmap/josm/io/OsmApiTest.java
diff --git test/unit/org/openstreetmap/josm/io/OsmApiTest.java test/unit/org/openstreetmap/josm/io/OsmApiTest.java index f5d9013f9a..79020c89da 100644
2 2 package org.openstreetmap.josm.io; 3 3 4 4 import static org.junit.jupiter.api.Assertions.assertEquals; 5 import static org.junit.jupiter.api.Assertions.assertNull; 6 import static org.junit.jupiter.api.Assertions.assertSame; 5 7 6 8 import java.io.ByteArrayInputStream; 7 9 import java.nio.charset.StandardCharsets; … … import org.junit.jupiter.api.Test; 10 12 import org.openstreetmap.josm.data.osm.Changeset; 11 13 import org.openstreetmap.josm.data.osm.User; 12 14 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 15 import org.openstreetmap.josm.spi.preferences.Config; 16 import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 13 17 14 18 /** 15 19 * Unit tests of {@link OsmApi} class. 16 20 */ 21 @BasicPreferences 22 @org.openstreetmap.josm.testutils.annotations.OsmApi 17 23 class OsmApiTest { 18 24 /** 19 25 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12675">Bug #12675</a>. … … class OsmApiTest { 36 42 NullProgressMonitor.INSTANCE).iterator().next(); 37 43 assertEquals(User.getAnonymous(), cs2.getUser()); 38 44 } 45 46 /** 47 * Unit test of {@link OsmApi#normalizeApiUrl}: white space and trailing slashes are removed. 48 */ 49 @Test 50 void testNormalizeApiUrl() { 51 assertEquals("https://example.com/api", OsmApi.normalizeApiUrl("https://example.com/api")); 52 assertEquals("https://example.com/api", OsmApi.normalizeApiUrl("https://example.com/api/")); 53 assertEquals("https://example.com/api", OsmApi.normalizeApiUrl("https://example.com/api///")); 54 assertEquals("https://example.com/api", OsmApi.normalizeApiUrl(" https://example.com/api/\t")); 55 assertEquals("https://example.com", OsmApi.normalizeApiUrl("https://example.com/")); 56 assertEquals("", OsmApi.normalizeApiUrl(" ")); 57 assertNull(OsmApi.normalizeApiUrl(null)); 58 // the slashes of the scheme must not be eaten 59 assertEquals("https://", OsmApi.normalizeApiUrl("https://")); 60 } 61 62 /** 63 * A URL which only differs by a trailing slash is the same API, and is stored without the slash. 64 */ 65 @Test 66 void testGetOsmApiIgnoresTrailingSlash() { 67 OsmApi api = OsmApi.getOsmApi("https://example.com/api/"); 68 assertEquals("https://example.com/api", api.getServerUrl()); 69 assertSame(api, OsmApi.getOsmApi("https://example.com/api")); 70 assertSame(api, OsmApi.getOsmApi(" https://example.com/api// ")); 71 } 72 73 /** 74 * An API URL stored with a trailing slash is used without it, so that code comparing it to a known URL or 75 * deriving another URL from it works. Non-regression test for the OAuth and "History (web)" breakage. 76 */ 77 @Test 78 void testTrailingSlashInPreference() { 79 Config.getPref().put("osm-server.url", "https://example.com/api/"); 80 assertEquals("https://example.com/api", OsmApi.getOsmApi().getServerUrl()); 81 assertEquals("https://example.com/api/", OsmApi.getOsmApi().getBaseUrl()); 82 } 39 83 }
