diff --git a/json/resources/intellij.json.xml b/json/resources/intellij.json.xml
index c387e6e3146a..fc029387a222 100644
--- a/json/resources/intellij.json.xml
+++ b/json/resources/intellij.json.xml
@@ -137,6 +137,8 @@
+
+
diff --git a/json/src/com/intellij/json/JsonWebReferenceContributor.java b/json/src/com/intellij/json/JsonWebReferenceContributor.java
new file mode 100644
index 000000000000..3776bd31d122
--- /dev/null
+++ b/json/src/com/intellij/json/JsonWebReferenceContributor.java
@@ -0,0 +1,56 @@
+// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.json;
+
+import com.intellij.json.psi.JsonProperty;
+import com.intellij.json.psi.JsonStringLiteral;
+import com.intellij.json.psi.JsonValue;
+import com.intellij.openapi.paths.GlobalPathReferenceProvider;
+import com.intellij.openapi.paths.WebReference;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+final class JsonWebReferenceContributor extends PsiReferenceContributor {
+ @Override
+ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
+ registrar.registerReferenceProvider(
+ psiElement(JsonStringLiteral.class),
+ new PsiReferenceProvider() {
+ @Override
+ public boolean acceptsTarget(@NotNull PsiElement target) {
+ return false; // web references do not point to any real PsiElement
+ }
+
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
+ if (!(element instanceof JsonStringLiteral)) return PsiReference.EMPTY_ARRAY;
+ JsonStringLiteral stringLiteral = (JsonStringLiteral)element;
+
+ PsiElement parent = stringLiteral.getParent();
+ if (!(parent instanceof JsonProperty)) return PsiReference.EMPTY_ARRAY;
+
+ JsonValue jsonValueElement = ((JsonProperty)parent).getValue();
+ if (element != jsonValueElement) return PsiReference.EMPTY_ARRAY;
+
+ if (element.getTextLength() > 1000) return PsiReference.EMPTY_ARRAY; // JSON may be used as data format for huge strings
+ if (!element.textContains(':')) return PsiReference.EMPTY_ARRAY;
+
+ String textValue = stringLiteral.getValue();
+
+ if (GlobalPathReferenceProvider.isWebReferenceUrl(textValue)) {
+ TextRange valueTextRange = ElementManipulators.getValueTextRange(stringLiteral);
+ if (valueTextRange.isEmpty()) return PsiReference.EMPTY_ARRAY;
+
+ return new PsiReference[]{new WebReference(element, valueTextRange, textValue)};
+ }
+
+ return PsiReference.EMPTY_ARRAY;
+ }
+ },
+ PsiReferenceRegistrar.LOWER_PRIORITY
+ );
+ }
+}
diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTest.java b/json/tests/test/com/intellij/json/JsonHighlightingTest.java
index 39f31fdd9834..2e6d0f2e886b 100644
--- a/json/tests/test/com/intellij/json/JsonHighlightingTest.java
+++ b/json/tests/test/com/intellij/json/JsonHighlightingTest.java
@@ -87,6 +87,10 @@ public class JsonHighlightingTest extends JsonHighlightingTestBase {
doTest();
}
+ public void testWebUrls() {
+ doTest();
+ }
+
public void testRainbow() {
myFixture.testRainbow("test.json",
"{\n" +
diff --git a/json/tests/testData/highlighting/WebUrls.json b/json/tests/testData/highlighting/WebUrls.json
new file mode 100644
index 000000000000..90c3a487a08e
--- /dev/null
+++ b/json/tests/testData/highlighting/WebUrls.json
@@ -0,0 +1,6 @@
+{
+ "some": "http://localhost",
+ "secure": "https://localhost",
+ "not-url": "https :// localhost",
+ "https://key-not-checked": "value"
+}
\ No newline at end of file