From e8538e801f2e42a197618565bfafa11c6bf8e506 Mon Sep 17 00:00:00 2001 From: nsingh Date: Tue, 8 Aug 2017 15:54:01 -0700 Subject: [PATCH 1/2] PT 145243139 - Static validation for health check endpoint Also added relevant JUnit. --- .../manifest/yaml/ManifestYmlSchema.java | 4 +- .../yaml/ManifestYmlValueParsers.java | 46 +++++++++ .../manifest/yaml/ManifestYamlEditorTest.java | 99 +++++++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) diff --git a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java index 5fa678fd3..30c538457 100644 --- a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java +++ b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlSchema.java @@ -147,11 +147,11 @@ public final class ManifestYmlSchema implements YamlSchema { YAtomicType t_boolean = f.yenum("boolean", "true", "false"); YAtomicType t_ne_string = f.yatomic("String"); - t_ne_string.parseWith(ValueParsers.NE_STRING); + t_ne_string.parseWith(ManifestYmlValueParsers.healthCheckEndpointPath()); t_application_name = f.yatomic("ApplicationName"); t_application_name.parseWith(ValueParsers.NE_STRING); - + YType t_string = f.yatomic("String"); t_route_string = f.yatomic("RouteUri") diff --git a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java index dfbe04635..c96a7b4c7 100644 --- a/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java +++ b/headless-services/manifest-yaml-language-server/src/main/java/org/springframework/ide/vscode/manifest/yaml/ManifestYmlValueParsers.java @@ -10,6 +10,9 @@ *******************************************************************************/ package org.springframework.ide.vscode.manifest.yaml; +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collection; import java.util.Set; import java.util.concurrent.Callable; @@ -18,6 +21,7 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemTy import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileException; import org.springframework.ide.vscode.commons.util.Assert; import org.springframework.ide.vscode.commons.util.EnumValueParser; +import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.util.ValueParser; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YAtomicType; @@ -104,4 +108,46 @@ public class ManifestYmlValueParsers { }; } + /** + * Parses an HTTP health check endpoint path. Note that this not parse the path portion of an HTTP URI, but verifies + * that the WHOLE value is a valid HTTP path, and therefore needs to start with an '/' + *

+ * Example: /appPath, /?check=true, /appPath/test.txt + * @return + */ + public static ValueParser healthCheckEndpointPath() { + return new ValueParser() { + + @Override + public Object parse(String pathVal) throws Exception { + String parsed = pathVal; + if (!StringUtil.hasText(pathVal)) { + throw new IllegalArgumentException("Path requires a value staring with '/'"); + } + else { + URI uri = URI.create(pathVal); + + if (uri.getScheme() != null) { + throw new IllegalArgumentException("Path contains scheme: " + uri.getScheme()); + } + if (uri.getHost() != null) { + throw new IllegalArgumentException("Path contains host: " + uri.getHost()); + } + if (uri.getPort() != -1 ) { + throw new IllegalArgumentException("Path contains port: " + uri.getPort()); + } + if (uri.getAuthority() != null) { + throw new IllegalArgumentException("Path contains authority: " + uri.getAuthority()); + } + + Path path = Paths.get(pathVal); + if (!path.startsWith("/")) { + throw new IllegalArgumentException("Path must start with a '/'"); + } + } + return parsed; + } + }; + } + } diff --git a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java index 7d0e201f1..7b4f10e95 100644 --- a/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java +++ b/headless-services/manifest-yaml-language-server/src/test/java/org/springframework/ide/vscode/manifest/yaml/ManifestYamlEditorTest.java @@ -555,6 +555,105 @@ public class ManifestYamlEditorTest { editor.assertProblems("health-check-http-endpoint|This has no effect unless `health-check-type` is `http` (but it is currently set to `process`)"); } + @Test public void reconcileHealthHttpEndpointValidation() throws Exception { + Editor editor; + Diagnostic problem; + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /health" + ); + editor.assertProblems(/*NONE*/); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /health/additionalpath" + ); + editor.assertProblems(/*NONE*/); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /health/applog.txt" + ); + editor.assertProblems(/*NONE*/); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /health?check=true" + ); + editor.assertProblems(/*NONE*/); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /?check=true" + ); + editor.assertProblems(/*NONE*/); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint:" + ); + problem = editor.assertProblems("|Path requires a value staring with '/'").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: health" + ); + problem = editor.assertProblems("health|Path must start with a '/'").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: ?check=true" + ); + problem = editor.assertProblems("?check=true|Path must start with a '/'").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: health/additionalpath" + ); + problem = editor.assertProblems("health/additionalpath|Path must start with a '/'").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: http://health/additionalpath" + ); + problem = editor.assertProblems("http://health/additionalpath|Path contains scheme").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + + editor = harness.newEditor( + "applications:\n" + + "- name: my-app\n" + + " health-check-type: http\n" + + " health-check-http-endpoint: /health/ additionalpath" + ); + problem = editor.assertProblems("/health/ additionalpath|Illegal character in path").get(0); + assertEquals(DiagnosticSeverity.Error, problem.getSeverity()); + } + @Test public void reconcileRoutesWithNoHost() throws Exception { Editor editor; From dfd1c64bdf065ac2d05d1064abb72f67ae5fd03d Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Wed, 9 Aug 2017 15:09:46 -0400 Subject: [PATCH 2/2] Switch to a specific commit of atom-languageclient --- atom-extensions/atom-commons/lib/jar-language-client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom-extensions/atom-commons/lib/jar-language-client.js b/atom-extensions/atom-commons/lib/jar-language-client.js index ebc46be07..5cc964bc7 100644 --- a/atom-extensions/atom-commons/lib/jar-language-client.js +++ b/atom-extensions/atom-commons/lib/jar-language-client.js @@ -10,12 +10,12 @@ const {AutoLanguageClient, DownloadFile} = require('atom-languageclient'); export class JarLanguageClient extends AutoLanguageClient { - constructor(serverDownloadUrl, serverHome) { + constructor(serverDownloadUrl, serverHome, serverLauncherJar) { super(); this.serverHome = serverHome; this.serverDownloadUrl = serverDownloadUrl; - this.serverLauncherJar = path.basename(url.parse(this.serverDownloadUrl).pathname); + this.serverLauncherJar = serverLauncherJar; } startServerProcess () {