From 15df3d392d36b26a8c1d09ab57f945b71b3f2564 Mon Sep 17 00:00:00 2001 From: Manuel Fuhr Date: Tue, 25 Oct 2022 07:13:56 +0200 Subject: [PATCH 1/5] Add testcase for param override --- .../java/btools/router/RoutingEngineTest.java | 24 ++++-- .../src/test/resources/paramTrack0.gpx | 76 +++++++++++++++++++ 2 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 brouter-core/src/test/resources/paramTrack0.gpx diff --git a/brouter-core/src/test/java/btools/router/RoutingEngineTest.java b/brouter-core/src/test/java/btools/router/RoutingEngineTest.java index ba2dc90..1f95be4 100644 --- a/brouter-core/src/test/java/btools/router/RoutingEngineTest.java +++ b/brouter-core/src/test/java/btools/router/RoutingEngineTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import java.io.File; import java.net.URL; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; public class RoutingEngineTest { @@ -22,22 +23,36 @@ public class RoutingEngineTest { @Test public void routeCrossingSegmentBorder() { - String msg = calcRoute(8.720897, 50.002515, 8.723658, 49.997510, "testtrack"); + String msg = calcRoute(8.720897, 50.002515, 8.723658, 49.997510, "testtrack", new RoutingContext()); // error message from router? Assert.assertNull("routing failed: " + msg, msg); // if the track didn't change, we expect the first alternative also File a1 = new File(workingDir, "testtrack1.gpx"); - Assert.assertTrue("result content missmatch", a1.exists()); + a1.deleteOnExit(); + Assert.assertTrue("result content mismatch", a1.exists()); } @Test public void routeDestinationPointFarOff() { - String msg = calcRoute(8.720897, 50.002515, 16.723658, 49.997510, "notrack"); + String msg = calcRoute(8.720897, 50.002515, 16.723658, 49.997510, "notrack", new RoutingContext()); Assert.assertTrue(msg, msg != null && msg.contains("not found")); } - private String calcRoute(double flon, double flat, double tlon, double tlat, String trackname) { + @Test + public void overrideParam() { + RoutingContext rctx = new RoutingContext(); + rctx.keyValues = new HashMap<>(); + rctx.keyValues.put("avoid_unsafe", "1.0"); + String msg = calcRoute(8.723037, 50.000491, 8.712737, 50.002899, "paramTrack", rctx); + Assert.assertNull("routing failed: " + msg, msg); + + File trackFile = new File(workingDir, "paramTrack1.gpx"); + trackFile.deleteOnExit(); + Assert.assertTrue("result content mismatch", trackFile.exists()); + } + + private String calcRoute(double flon, double flat, double tlon, double tlat, String trackname, RoutingContext rctx) { String wd = workingDir.getAbsolutePath(); List wplist = new ArrayList<>(); @@ -54,7 +69,6 @@ public class RoutingEngineTest { n.ilat = 90000000 + (int) (tlat * 1000000 + 0.5); wplist.add(n); - RoutingContext rctx = new RoutingContext(); rctx.localFunction = wd + "/../../../../misc/profiles2/trekking.brf"; RoutingEngine re = new RoutingEngine( diff --git a/brouter-core/src/test/resources/paramTrack0.gpx b/brouter-core/src/test/resources/paramTrack0.gpx new file mode 100644 index 0000000..f3de18c --- /dev/null +++ b/brouter-core/src/test/resources/paramTrack0.gpx @@ -0,0 +1,76 @@ + + + + + brouter_trekking_0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fed171fd06137cc020fb3ed9e50798454b404e6e Mon Sep 17 00:00:00 2001 From: Manuel Fuhr Date: Wed, 26 Oct 2022 07:44:42 +0200 Subject: [PATCH 2/5] Tests for RouteServer --- brouter-server/build.gradle | 4 +- .../btools/server/request/RequestHandler.java | 6 +- .../btools/server/RequestHandlerTest.java | 27 ++++ .../java/btools/server/RouteServerTest.java | 115 ++++++++++++++++++ 4 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 brouter-server/src/test/java/btools/server/RequestHandlerTest.java create mode 100644 brouter-server/src/test/java/btools/server/RouteServerTest.java diff --git a/brouter-server/build.gradle b/brouter-server/build.gradle index 2e377ab..c52d524 100644 --- a/brouter-server/build.gradle +++ b/brouter-server/build.gradle @@ -70,8 +70,6 @@ distributions { } dependencies { - testImplementation 'junit:junit:4.13.1' - implementation project(':brouter-codec') implementation project(':brouter-core') implementation project(':brouter-expressions') @@ -79,4 +77,6 @@ dependencies { implementation project(':brouter-mapaccess') implementation project(':brouter-util') + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.json:json:20180813' } diff --git a/brouter-server/src/main/java/btools/server/request/RequestHandler.java b/brouter-server/src/main/java/btools/server/request/RequestHandler.java index fb69d30..5364c5b 100644 --- a/brouter-server/src/main/java/btools/server/request/RequestHandler.java +++ b/brouter-server/src/main/java/btools/server/request/RequestHandler.java @@ -1,7 +1,7 @@ package btools.server.request; -import java.util.HashMap; import java.util.List; +import java.util.Map; import btools.router.OsmNodeNamed; import btools.router.OsmTrack; @@ -10,9 +10,9 @@ import btools.server.ServiceContext; public abstract class RequestHandler { protected ServiceContext serviceContext; - protected HashMap params; + protected Map params; - public RequestHandler(ServiceContext serviceContext, HashMap params) { + public RequestHandler(ServiceContext serviceContext, Map params) { this.serviceContext = serviceContext; this.params = params; } diff --git a/brouter-server/src/test/java/btools/server/RequestHandlerTest.java b/brouter-server/src/test/java/btools/server/RequestHandlerTest.java new file mode 100644 index 0000000..2d5f698 --- /dev/null +++ b/brouter-server/src/test/java/btools/server/RequestHandlerTest.java @@ -0,0 +1,27 @@ +package btools.server; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.HashMap; + +import btools.router.RoutingContext; +import btools.server.request.ServerHandler; + +public class RequestHandlerTest { + @Test + @Ignore("Parameters are currently handled by RouteServer, not RequestHandler") + public void parseParameters() { + HashMap params = new HashMap<>(); + params.put("lonlats", "8.799297,49.565883|8.811764,49.563606"); + params.put("profile", "trekking"); + params.put("alternativeidx", "0"); + params.put("profile:test", "bar"); + ServerHandler serverHandler = new ServerHandler(null, params); + RoutingContext routingContext = serverHandler.readRoutingContext(); + + Assert.assertEquals("trekking", routingContext.localFunction); + Assert.assertEquals("bar", routingContext.keyValues.get("test")); + } +} diff --git a/brouter-server/src/test/java/btools/server/RouteServerTest.java b/brouter-server/src/test/java/btools/server/RouteServerTest.java new file mode 100644 index 0000000..a1bc161 --- /dev/null +++ b/brouter-server/src/test/java/btools/server/RouteServerTest.java @@ -0,0 +1,115 @@ +package btools.server; + + +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +public class RouteServerTest { + private static final String host = "localhost"; + private static final String port = "17777"; + private static final String baseUrl = "http://" + host + ":" + port + "/"; + + @BeforeClass + public static void setupServer() throws IOException { + File workingDir = new File(".").getCanonicalFile(); + File segmentDir = new File(workingDir, "../brouter-map-creator/build/resources/test/tmp/segments"); + File profileDir = new File(workingDir, "../misc/profiles2"); + File customProfileDir = workingDir; + + Runnable runnable = () -> { + try { + RouteServer.main(new String[]{segmentDir.getAbsolutePath(), profileDir.getAbsolutePath(), customProfileDir.getAbsolutePath(), port, "1"}); + } catch (Exception e) { + e.printStackTrace(); + } + }; + + Thread thread = new Thread(runnable); + thread.start(); + + // Busy-wait for server startup + URL requestUrl = new URL(baseUrl); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + for (int i = 10; i >= 0; i--) { + try { + httpConnection.setConnectTimeout(10); + httpConnection.connect(); + break; + } catch (ConnectException e) { + if (i == 0) { + throw e; + } + } + } + } + + @Test + public void defaultRouteTrekking() throws IOException { + URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.723037,50.000491|8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson"); + + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + + InputStream inputStream = httpConnection.getInputStream(); + JSONObject geoJson = new JSONObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); + Assert.assertEquals("1204", geoJson.query("/features/0/properties/track-length")); + } + + @Test + public void overrideParameter() throws IOException { + URL requestUrl = new URL(baseUrl + "brouter?lonlats=8.723037,50.000491|8.712737,50.002899&nogos=&profile=trekking&alternativeidx=0&format=geojson&profile:avoid_unsafe=1"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + + InputStream inputStream = httpConnection.getInputStream(); + JSONObject geoJson = new JSONObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); + Assert.assertEquals("1902", geoJson.query("/features/0/properties/track-length")); + } + + @Test + public void robots() throws IOException { + URL requestUrl = new URL(baseUrl + "robots.txt"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + + String content = new String(httpConnection.getInputStream().readAllBytes(), StandardCharsets.UTF_8); + Assert.assertTrue(content.contains("Disallow: /")); + } + + @Test + public void invalidUrl() throws IOException { + URL requestUrl = new URL(baseUrl + "invalid"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, httpConnection.getResponseCode()); + } + + @Test + @Ignore("Broken implementation (uppercase / lowercase issue)") + public void invalidReferrer() throws IOException { + URL requestUrl = new URL(baseUrl + "brouter/%7C/%2C"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + httpConnection.setRequestProperty("Referer", "http://brouter.de/brouter-web/"); + httpConnection.connect(); + + Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, httpConnection.getResponseCode()); + } +} From 3a4d743eb59563aa1c7896e215002a5cfbaad7b3 Mon Sep 17 00:00:00 2001 From: Manuel Fuhr Date: Fri, 28 Oct 2022 17:28:21 +0200 Subject: [PATCH 3/5] Increase startup timeout --- .../src/test/java/btools/server/RouteServerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/brouter-server/src/test/java/btools/server/RouteServerTest.java b/brouter-server/src/test/java/btools/server/RouteServerTest.java index a1bc161..e3b1a12 100644 --- a/brouter-server/src/test/java/btools/server/RouteServerTest.java +++ b/brouter-server/src/test/java/btools/server/RouteServerTest.java @@ -21,7 +21,7 @@ public class RouteServerTest { private static final String baseUrl = "http://" + host + ":" + port + "/"; @BeforeClass - public static void setupServer() throws IOException { + public static void setupServer() throws IOException, InterruptedException { File workingDir = new File(".").getCanonicalFile(); File segmentDir = new File(workingDir, "../brouter-map-creator/build/resources/test/tmp/segments"); File profileDir = new File(workingDir, "../misc/profiles2"); @@ -41,15 +41,16 @@ public class RouteServerTest { // Busy-wait for server startup URL requestUrl = new URL(baseUrl); HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); - for (int i = 10; i >= 0; i--) { + for (int i = 20; i >= 0; i--) { try { - httpConnection.setConnectTimeout(10); + httpConnection.setConnectTimeout(1000); httpConnection.connect(); break; } catch (ConnectException e) { if (i == 0) { throw e; } + Thread.sleep(100); } } } From 06f0315cf4c87f010b639424b30e8b62ebdbbf84 Mon Sep 17 00:00:00 2001 From: Manuel Fuhr Date: Fri, 28 Oct 2022 19:44:37 +0200 Subject: [PATCH 4/5] Remove broken spam/referrer handling --- .../src/main/java/btools/server/RouteServer.java | 16 ---------------- .../test/java/btools/server/RouteServerTest.java | 12 ------------ 2 files changed, 28 deletions(-) diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 62c74e5..24abb13 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -81,7 +81,6 @@ public class RouteServer extends Thread implements Comparable { String agent = null; String encodings = null; String xff = null; // X-Forwarded-For - String referer = null; // more headers until first empty line for (; ; ) { @@ -108,12 +107,6 @@ public class RouteServer extends Thread implements Comparable { if (line.startsWith("x-forwarded-for: ")) { xff = line.substring("x-forwarded-for: ".length()); } - if (line.startsWith("Referer: ")) { - referer = line.substring("Referer: ".length()); - } - if (line.startsWith("Referrer: ")) { - referer = line.substring("Referrer: ".length()); - } } InetAddress ip = clientSocket.getInetAddress(); @@ -139,15 +132,6 @@ public class RouteServer extends Thread implements Comparable { } } - if (referer != null && referer.indexOf("brouter.de/brouter-web") >= 0) { - if (getline.indexOf("%7C") >= 0 && getline.indexOf("%2C") >= 0) { - writeHttpHeader(bw, HTTP_STATUS_FORBIDDEN); - bw.write("Spam? please stop"); - bw.flush(); - return; - } - } - if (getline.startsWith("GET /favicon.ico")) { writeHttpHeader(bw, HTTP_STATUS_NOT_FOUND); bw.flush(); diff --git a/brouter-server/src/test/java/btools/server/RouteServerTest.java b/brouter-server/src/test/java/btools/server/RouteServerTest.java index e3b1a12..7babe6a 100644 --- a/brouter-server/src/test/java/btools/server/RouteServerTest.java +++ b/brouter-server/src/test/java/btools/server/RouteServerTest.java @@ -4,7 +4,6 @@ package btools.server; import org.json.JSONObject; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import java.io.File; @@ -102,15 +101,4 @@ public class RouteServerTest { Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, httpConnection.getResponseCode()); } - - @Test - @Ignore("Broken implementation (uppercase / lowercase issue)") - public void invalidReferrer() throws IOException { - URL requestUrl = new URL(baseUrl + "brouter/%7C/%2C"); - HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); - httpConnection.setRequestProperty("Referer", "http://brouter.de/brouter-web/"); - httpConnection.connect(); - - Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, httpConnection.getResponseCode()); - } } From 556555b8ae66d1e3e740c18c8a5f14b3f9121269 Mon Sep 17 00:00:00 2001 From: Manuel Fuhr Date: Sat, 29 Oct 2022 20:33:47 +0200 Subject: [PATCH 5/5] Test profile upload --- .../java/btools/server/RouteServerTest.java | 71 ++++++++++++++++++- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/brouter-server/src/test/java/btools/server/RouteServerTest.java b/brouter-server/src/test/java/btools/server/RouteServerTest.java index 7babe6a..e5d3521 100644 --- a/brouter-server/src/test/java/btools/server/RouteServerTest.java +++ b/brouter-server/src/test/java/btools/server/RouteServerTest.java @@ -4,31 +4,42 @@ package btools.server; import org.json.JSONObject; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; public class RouteServerTest { private static final String host = "localhost"; private static final String port = "17777"; private static final String baseUrl = "http://" + host + ":" + port + "/"; + @ClassRule + public static TemporaryFolder profileDir = new TemporaryFolder(); + @BeforeClass public static void setupServer() throws IOException, InterruptedException { File workingDir = new File(".").getCanonicalFile(); File segmentDir = new File(workingDir, "../brouter-map-creator/build/resources/test/tmp/segments"); - File profileDir = new File(workingDir, "../misc/profiles2"); - File customProfileDir = workingDir; + File profileSourceDir = new File(workingDir, "../misc/profiles2"); + // Copy required files to temporary dir because profile upload will create files + Files.copy(Paths.get(profileSourceDir.getAbsolutePath(), "lookups.dat"), Paths.get(profileDir.getRoot().getAbsolutePath(), "lookups.dat")); + Files.copy(Paths.get(profileSourceDir.getAbsolutePath(), "trekking.brf"), Paths.get(profileDir.getRoot().getAbsolutePath(), "trekking.brf")); + String customProfileDir = "custom"; Runnable runnable = () -> { try { - RouteServer.main(new String[]{segmentDir.getAbsolutePath(), profileDir.getAbsolutePath(), customProfileDir.getAbsolutePath(), port, "1"}); + RouteServer.main(new String[]{segmentDir.getAbsolutePath(), profileDir.getRoot().getAbsolutePath(), customProfileDir, port, "1"}); } catch (Exception e) { e.printStackTrace(); } @@ -81,6 +92,60 @@ public class RouteServerTest { Assert.assertEquals("1902", geoJson.query("/features/0/properties/track-length")); } + @Test + public void uploadValidProfile() throws IOException { + URL requestUrl = new URL(baseUrl + "brouter/profile"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + + httpConnection.setRequestMethod("POST"); + httpConnection.setDoOutput(true); + String dummyProfile = "---context:global # following code refers to global config\n" + + "\n" + + "# this prevents suppression of unused tags, so they are visibly in the data tab\n" + + "assign processUnusedTags = true\n" + + "assign validForFoot = true\n" + + "\n" + + "---context:way # following code refers to way-tags\n" + + "\n" + + "assign costfactor\n" + + " switch and highway= not route=ferry 100000 1\n" + + "\n" + + "---context:node # following code refers to node tags\n" + + "assign initialcost = 0\n"; + try (OutputStream outputStream = httpConnection.getOutputStream()) { + outputStream.write(dummyProfile.getBytes(StandardCharsets.UTF_8)); + } + + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + InputStream inputStream = httpConnection.getInputStream(); + String response = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + JSONObject jsonResponse = new JSONObject(response); + Assert.assertTrue(jsonResponse.query("/profileid").toString().startsWith("custom_")); + Assert.assertFalse(jsonResponse.has("error")); + } + + @Test + public void uploadInvalidProfile() throws IOException { + URL requestUrl = new URL(baseUrl + "brouter/profile"); + HttpURLConnection httpConnection = (HttpURLConnection) requestUrl.openConnection(); + + httpConnection.setRequestMethod("POST"); + httpConnection.setDoOutput(true); + String invalidProfile = ""; + try (OutputStream outputStream = httpConnection.getOutputStream()) { + outputStream.write(invalidProfile.getBytes(StandardCharsets.UTF_8)); + } + + // It would be better if RouteServer would return "400 Bad Request" + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpConnection.getResponseCode()); + InputStream inputStream = httpConnection.getInputStream(); + String response = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + JSONObject jsonResponse = new JSONObject(response); + // Returns profileid, but profile isn't valid + Assert.assertTrue(jsonResponse.query("/profileid").toString().startsWith("custom_")); + Assert.assertTrue(jsonResponse.has("error")); + } + @Test public void robots() throws IOException { URL requestUrl = new URL(baseUrl + "robots.txt");