aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--application/pom.xml30
-rw-r--r--client/go/script-utils/startcbinary/tuning.go41
-rw-r--r--client/go/util/setrlimit.go13
-rw-r--r--client/go/util/tuning.go69
-rw-r--r--client/js/app/src/app/pages/querybuilder/context/parameters.jsx1
-rw-r--r--cloud-tenant-base-dependencies-enforcer/pom.xml9
-rw-r--r--config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java6
-rw-r--r--config-model/src/test/java/com/yahoo/schema/derived/CasedIndexTestCase.java48
-rw-r--r--container-core/pom.xml93
-rw-r--r--container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java16
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java2
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java25
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FixedHTTP2ServerConnectionFactory.java122
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java29
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java10
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java58
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java10
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java23
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java13
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java31
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java6
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java6
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java4
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java8
-rw-r--r--container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def3
-rw-r--r--container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def3
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java4
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java2
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java6
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java18
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java1
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java19
-rw-r--r--container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java19
-rw-r--r--container-dev/pom.xml20
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/VespaLowercasingSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/YqlParser.java7
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/UserInputTestCase.java7
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java6
-rw-r--r--container-test/pom.xml20
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java2
-rw-r--r--parent/pom.xml30
-rwxr-xr-xscrewdriver/release-java-artifacts.sh2
-rw-r--r--vespa-hadoop/pom.xml65
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java3
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/KeygenTool.java11
-rw-r--r--vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/TokenInfoTool.java56
-rw-r--r--vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java26
-rw-r--r--vespaclient-java/src/test/resources/expected-help-output.txt2
-rw-r--r--vespaclient-java/src/test/resources/expected-token-info-help-output.txt5
-rw-r--r--vespaclient-java/src/test/resources/expected-token-info-output.txt4
55 files changed, 739 insertions, 304 deletions
diff --git a/application/pom.xml b/application/pom.xml
index 8f9dc7999a0..2f0586145b2 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -139,8 +139,8 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -152,35 +152,43 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
- <scope>test</scope>
+ <artifactId>jetty-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
- <scope>test</scope>
+ <artifactId>jetty-util</artifactId>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
+ </dependency>
+ <!-- END JETTY embedded jars -->
+
+ <dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
@@ -190,8 +198,6 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
- <!-- END JETTY embedded jars -->
-
</dependencies>
<build>
diff --git a/client/go/script-utils/startcbinary/tuning.go b/client/go/script-utils/startcbinary/tuning.go
index dbe4d34dabe..950842babd6 100644
--- a/client/go/script-utils/startcbinary/tuning.go
+++ b/client/go/script-utils/startcbinary/tuning.go
@@ -4,47 +4,10 @@
package startcbinary
import (
- "os"
- "strconv"
- "strings"
-
- "github.com/vespa-engine/vespa/client/go/trace"
"github.com/vespa-engine/vespa/client/go/util"
)
-func (spec *ProgSpec) optionallyReduceBaseFrequency() {
- if spec.getenv(ENV_VESPA_TIMER_HZ) == "" {
- backticks := util.BackTicksIgnoreStderr
- out, _ := backticks.Run("uname", "-r")
- if strings.Contains(out, "linuxkit") {
- trace.Trace("Running docker on macos. Reducing base frequency from 1000hz to 100hz due to high cost of sampling time. This will reduce timeout accuracy.")
- spec.setenv(ENV_VESPA_TIMER_HZ, "100")
- }
- }
-}
-
-func getThpSizeMb() int {
- const fn = "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
- thp_size := 2
- line, err := os.ReadFile(fn)
- if err == nil {
- chomped := strings.TrimSuffix(string(line), "\n")
- number, err := strconv.Atoi(chomped)
- if err == nil {
- thp_size = number / (1024 * 1024)
- trace.Trace("thp_size", chomped, "=>", thp_size)
- } else {
- trace.Trace("no thp_size:", err)
- }
- } else {
- trace.Trace("no thp_size:", err)
- }
- return thp_size
-}
-
func (spec *ProgSpec) configureTuning() {
- spec.optionallyReduceBaseFrequency()
- util.SetResourceLimit(util.RLIMIT_CORE, util.NO_RLIMIT)
- util.SetResourceLimit(util.RLIMIT_NOFILE, 262144)
- util.SetResourceLimit(util.RLIMIT_NPROC, 409600)
+ util.OptionallyReduceTimerFrequency()
+ util.TuneResourceLimits()
}
diff --git a/client/go/util/setrlimit.go b/client/go/util/setrlimit.go
index 4ec1ea60a3c..6a78e47d35b 100644
--- a/client/go/util/setrlimit.go
+++ b/client/go/util/setrlimit.go
@@ -5,9 +5,11 @@
package util
import (
+ "os"
+ "strconv"
+
"github.com/vespa-engine/vespa/client/go/trace"
"golang.org/x/sys/unix"
- "os"
)
type ResourceId int
@@ -31,6 +33,13 @@ func (rid ResourceId) String() string {
return "unknown resource id"
}
+func readableLimit(val uint64) string {
+ if val == NO_RLIMIT {
+ return "unlimited"
+ }
+ return strconv.FormatUint(val, 10)
+}
+
func SetResourceLimit(resource ResourceId, newVal uint64) {
var current unix.Rlimit
err := unix.Getrlimit(int(resource), &current)
@@ -57,6 +66,6 @@ func SetResourceLimit(resource ResourceId, newVal uint64) {
if err != nil {
trace.Trace("Failed setting resource limit:", err)
} else {
- trace.Trace("Resource limit", resource, "adjusted OK:", wanted.Cur, "/", wanted.Max)
+ trace.Trace("Resource limit", resource, "adjusted OK:", readableLimit(wanted.Cur), "/", readableLimit(wanted.Max))
}
}
diff --git a/client/go/util/tuning.go b/client/go/util/tuning.go
new file mode 100644
index 00000000000..a8f6eab286a
--- /dev/null
+++ b/client/go/util/tuning.go
@@ -0,0 +1,69 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+package util
+
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/vespa-engine/vespa/client/go/trace"
+)
+
+const (
+ ENV_VESPA_TIMER_HZ = "VESPA_TIMER_HZ"
+)
+
+func OptionallyReduceTimerFrequency() {
+ if os.Getenv(ENV_VESPA_TIMER_HZ) == "" {
+ backticks := BackTicksIgnoreStderr
+ out, _ := backticks.Run("uname", "-r")
+ if strings.Contains(out, "linuxkit") {
+ trace.Trace(
+ "Running docker on macos.",
+ "Reducing base frequency from 1000hz to 100hz due to high cost of sampling time.",
+ "This will reduce timeout accuracy.")
+ os.Setenv(ENV_VESPA_TIMER_HZ, "100")
+ }
+ }
+}
+
+func TuneResourceLimits() {
+ var numfiles uint64 = 262144
+ var numprocs uint64 = 409600
+ if env := os.Getenv("file_descriptor_limit"); env != "" {
+ n, err := strconv.Atoi(env)
+ if err != nil {
+ numfiles = uint64(n)
+ }
+ }
+ if env := os.Getenv("num_processes_limit"); env != "" {
+ n, err := strconv.Atoi(env)
+ if err != nil {
+ numprocs = uint64(n)
+ }
+ }
+ SetResourceLimit(RLIMIT_CORE, NO_RLIMIT)
+ SetResourceLimit(RLIMIT_NOFILE, numfiles)
+ SetResourceLimit(RLIMIT_NPROC, numprocs)
+}
+
+func GetThpSizeMb() int {
+ const fn = "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
+ thp_size := 2
+ line, err := os.ReadFile(fn)
+ if err == nil {
+ chomped := strings.TrimSuffix(string(line), "\n")
+ number, err := strconv.Atoi(chomped)
+ if err == nil {
+ thp_size = number / (1024 * 1024)
+ trace.Trace("thp_size", chomped, "=>", thp_size)
+ } else {
+ trace.Trace("no thp_size:", err)
+ }
+ } else {
+ trace.Trace("no thp_size:", err)
+ }
+ return thp_size
+}
diff --git a/client/js/app/src/app/pages/querybuilder/context/parameters.jsx b/client/js/app/src/app/pages/querybuilder/context/parameters.jsx
index 377d60bfcd7..0143b2c1538 100644
--- a/client/js/app/src/app/pages/querybuilder/context/parameters.jsx
+++ b/client/js/app/src/app/pages/querybuilder/context/parameters.jsx
@@ -114,6 +114,7 @@ export default param('root', [
param('metrics', [param('ignore', 'Boolean', { default: false })]),
param('weakAnd', [param('replace', 'Boolean', { default: false })]),
param('wand', [param('hits', 'Integer', { default: 100 })]),
+ param('sorting', [param('degrading', 'Boolean', { default: true })]),
param('streaming', [
param('userid', 'Integer'),
diff --git a/cloud-tenant-base-dependencies-enforcer/pom.xml b/cloud-tenant-base-dependencies-enforcer/pom.xml
index 03f14d7d65f..8ba9794d75c 100644
--- a/cloud-tenant-base-dependencies-enforcer/pom.xml
+++ b/cloud-tenant-base-dependencies-enforcer/pom.xml
@@ -43,8 +43,7 @@
<javax.servlet-api.version>3.1.0</javax.servlet-api.version>
<javax.ws.rs-api.version>2.0.1</javax.ws.rs-api.version>
<jaxb.version>2.3.0</jaxb.version>
- <jetty.version>9.4.49.v20220914</jetty.version>
- <jetty-alpn.version>1.1.3.v20160715</jetty-alpn.version>
+ <jetty.version>11.0.12</jetty.version>
<org.lz4.version>1.8.0</org.lz4.version>
<org.json.version>20220320</org.json.version> <!-- TODO: Remove on Vespa 9 -->
<slf4j.version>1.7.32</slf4j.version> <!-- WARNING: when updated, also update c.y.v.tenant:base pom -->
@@ -200,22 +199,20 @@
<include>org.bouncycastle:bcpkix-jdk18on:[${bouncycastle.version}]:jar:test</include>
<include>org.bouncycastle:bcprov-jdk18on:[${bouncycastle.version}]:jar:test</include>
<include>org.bouncycastle:bcutil-jdk18on:[${bouncycastle.version}]:jar:test</include>
- <include>org.eclipse.jetty.alpn:alpn-api:[${jetty-alpn.version}]:jar:test</include>
<include>org.eclipse.jetty.http2:http2-common:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty.http2:http2-hpack:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty.http2:http2-server:[${jetty.version}]:jar:test</include>
+ <include>org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api:5.0.2:jar:test</include>
+ <include>org.eclipse.jetty:jetty-alpn-client:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-alpn-java-server:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-alpn-server:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-client:[${jetty.version}]:jar:test</include>
- <include>org.eclipse.jetty:jetty-continuation:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-http:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-io:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-jmx:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-security:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-server:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-servlet:[${jetty.version}]:jar:test</include>
- <include>org.eclipse.jetty:jetty-servlets:[${jetty.version}]:jar:test</include>
- <include>org.eclipse.jetty:jetty-util-ajax:[${jetty.version}]:jar:test</include>
<include>org.eclipse.jetty:jetty-util:[${jetty.version}]:jar:test</include>
<include>org.hamcrest:hamcrest-core:1.3:jar:test</include>
<include>org.hdrhistogram:HdrHistogram:2.1.8:jar:test</include>
diff --git a/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java b/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java
index 277858bed26..54c503a0bbd 100644
--- a/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java
+++ b/config-model/src/main/java/com/yahoo/schema/derived/IndexInfo.java
@@ -189,9 +189,9 @@ public class IndexInfo extends Derived implements IndexInfoConfig.Producer {
}
private static boolean needLowerCase(ImmutableSDField field) {
- return field.doesIndexing()
- || field.doesLowerCasing()
- || ((field.doesAttributing() || (field.getAttribute() != null))
+ return ( field.doesIndexing() && field.getMatching().getCase() != Case.CASED)
+ || field.doesLowerCasing()
+ || ((field.doesAttributing() || (field.getAttribute() != null))
&& isAnyChildString(field.getDataType())
&& field.getMatching().getCase().equals(Case.UNCASED));
}
diff --git a/config-model/src/test/java/com/yahoo/schema/derived/CasedIndexTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/CasedIndexTestCase.java
new file mode 100644
index 00000000000..68a5a7b26db
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/schema/derived/CasedIndexTestCase.java
@@ -0,0 +1,48 @@
+package com.yahoo.schema.derived;
+
+import com.yahoo.schema.ApplicationBuilder;
+import com.yahoo.search.config.IndexInfoConfig;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+/**
+ * @author bratseth
+ */
+public class CasedIndexTestCase {
+
+ @Test
+ public void testCasedIndexDeriving() throws Exception {
+ var b = new ApplicationBuilder();
+ b.addSchema("""
+ schema test {
+ document test {
+ field a type string {
+ indexing: summary | index
+ match: cased
+ }
+ }
+ }
+ """);
+ var application = b.build(true);
+ var config = new DerivedConfiguration(application.schemas().get("test"), b.getRankProfileRegistry());
+ var indexInfo = config.getIndexInfo();
+ var indexInfoConfigBuilder = new IndexInfoConfig.Builder();
+ indexInfo.getConfig(indexInfoConfigBuilder);
+ assertFalse(commandsOf("test", "a", indexInfoConfigBuilder).contains("lowercase"));
+ }
+
+ private Set<String> commandsOf(String schema, String field, IndexInfoConfig.Builder indexInfoConfigBuilder) {
+ var schemaIndexInfo = indexInfoConfigBuilder.build().indexinfo().stream()
+ .filter(c -> c.name().equals(schema))
+ .findAny().get();
+ return schemaIndexInfo.command().stream()
+ .filter(c -> c.indexname().equals(field))
+ .map(c -> c.command())
+ .collect(Collectors.toSet());
+ }
+
+}
diff --git a/container-core/pom.xml b/container-core/pom.xml
index ed4b05495e3..52d7f3372f0 100644
--- a/container-core/pom.xml
+++ b/container-core/pom.xml
@@ -14,6 +14,7 @@
<artifactId>container-core</artifactId>
<version>8-SNAPSHOT</version>
<packaging>container-plugin</packaging>
+
<dependencies>
<!-- COMPILE scope -->
@@ -114,40 +115,119 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
+ <!-- Required for JDK9ServerALPNProcessor through ServiceLoader API -->
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</dependency>
<!-- END JETTY embedded jars -->
@@ -256,11 +336,6 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<scope>provided</scope>
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java b/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
index 104d2f8ae4a..f974eb5f26c 100644
--- a/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
+++ b/container-core/src/main/java/com/yahoo/container/jdisc/utils/MultiPartFormParser.java
@@ -2,9 +2,9 @@
package com.yahoo.container.jdisc.utils;
import com.yahoo.container.jdisc.HttpRequest;
-import org.eclipse.jetty.http.MultiPartFormInputStream;
+import jakarta.servlet.http.Part;
+import org.eclipse.jetty.server.MultiPartFormInputStream;
-import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java b/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
index b194124294c..c2faa1cd10a 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/Cookie.java
@@ -2,7 +2,7 @@
package com.yahoo.jdisc.http;
import org.eclipse.jetty.http.HttpCookie;
-import org.eclipse.jetty.server.CookieCutter;
+import org.eclipse.jetty.server.Cookies;
import java.util.Arrays;
import java.util.HashSet;
@@ -180,7 +180,7 @@ public class Cookie {
}
public static List<Cookie> fromCookieHeader(String headerVal) {
- CookieCutter cookieCutter = new CookieCutter();
+ Cookies cookieCutter = new Cookies();
cookieCutter.addCookieField(headerVal);
return Arrays.stream(cookieCutter.getCookies())
.map(servletCookie -> {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java b/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
index 598a924b327..4ad38a9f965 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/HttpRequest.java
@@ -8,15 +8,14 @@ import com.yahoo.jdisc.handler.ContentChannel;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.service.CurrentContainer;
-import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.UrlEncoded;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.security.Principal;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -116,15 +115,10 @@ public class HttpRequest extends Request {
}
private static Map<String, List<String>> getUriQueryParameters(URI uri) {
- MultiMap<String> queryParameters = new MultiMap<>();
- new HttpURI(uri).decodeQueryTo(queryParameters);
-
- // Do a deep copy so we do not leak Jetty classes outside
- Map<String, List<String>> deepCopiedQueryParameters = new HashMap<>();
- for (Map.Entry<String, List<String>> entry : queryParameters.entrySet()) {
- deepCopiedQueryParameters.put(entry.getKey(), new ArrayList<>(entry.getValue()));
- }
- return deepCopiedQueryParameters;
+ if (uri.getRawQuery() == null) return Map.of();
+ MultiMap<String> params = new MultiMap<>();
+ UrlEncoded.decodeUtf8To(uri.getRawQuery(), params);
+ return Map.copyOf(params);
}
public Method getMethod() {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
index 13a63efeaa9..5b51eeee7d6 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/AccessLogRequestLog.java
@@ -8,6 +8,7 @@ import com.yahoo.container.logging.RequestLog;
import com.yahoo.container.logging.RequestLogEntry;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.ServerConfig;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.http2.HTTP2Stream;
import org.eclipse.jetty.http2.server.HttpTransportOverHTTP2;
import org.eclipse.jetty.server.HttpChannel;
@@ -16,7 +17,6 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
-import javax.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
index 6282e334409..6632a9f6cf8 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
@@ -9,6 +9,8 @@ import com.yahoo.jdisc.http.ssl.impl.DefaultConnectorSsl;
import com.yahoo.security.tls.MixedMode;
import com.yahoo.security.tls.TransportSecurityUtils;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http.HttpCompliance;
+import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
@@ -137,8 +139,17 @@ public class ConnectorFactory {
httpConfig.setOutputBufferSize(connectorConfig.outputBufferSize());
httpConfig.setRequestHeaderSize(connectorConfig.requestHeaderSize());
httpConfig.setResponseHeaderSize(connectorConfig.responseHeaderSize());
+
+ // Disable use of ByteBuffer.allocateDirect()
+ httpConfig.setUseInputDirectByteBuffers(false);
+ httpConfig.setUseOutputDirectByteBuffers(false);
+
+ httpConfig.setHttpCompliance(HttpCompliance.RFC7230);
+ // TODO Vespa 9 Use default URI compliance (LEGACY == old Jetty 9.4 compliance)
+ httpConfig.setUriCompliance(UriCompliance.LEGACY);
if (isSslEffectivelyEnabled(connectorConfig)) {
- httpConfig.addCustomizer(new SecureRequestCustomizer());
+ // Explicitly disable SNI checking as Jetty's SNI checking trust manager is not part of our SSLContext trust manager chain
+ httpConfig.addCustomizer(new SecureRequestCustomizer(false, false, -1, false));
}
String serverNameFallback = connectorConfig.serverName().fallback();
if (!serverNameFallback.isBlank()) httpConfig.setServerAuthority(new HostPort(serverNameFallback));
@@ -150,7 +161,7 @@ public class ConnectorFactory {
}
private HTTP2ServerConnectionFactory newHttp2ConnectionFactory() {
- HTTP2ServerConnectionFactory factory = new HTTP2ServerConnectionFactory(newHttpConfiguration());
+ HTTP2ServerConnectionFactory factory = new FixedHTTP2ServerConnectionFactory(newHttpConfiguration());
setHttp2Config(factory);
return factory;
}
@@ -169,12 +180,14 @@ public class ConnectorFactory {
}
private SslConnectionFactory newSslConnectionFactory(Metric metric, ConnectionFactory wrappedFactory) {
- SslConnectionFactory connectionFactory = new SslConnectionFactory(createSslContextFactory(), wrappedFactory.getProtocol());
- connectionFactory.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort()));
- return connectionFactory;
+ var fac = new SslConnectionFactory(createSslContextFactory(), wrappedFactory.getProtocol());
+ fac.setDirectBuffersForDecryption(false);
+ fac.setDirectBuffersForDecryption(false);
+ fac.addBean(new SslHandshakeFailedListener(metric, connectorConfig.name(), connectorConfig.listenPort()));
+ return fac;
}
- private SslContextFactory createSslContextFactory() {
+ private SslContextFactory.Server createSslContextFactory() {
DefaultConnectorSsl ssl = new DefaultConnectorSsl();
sslProvider.configureSsl(ssl, connectorConfig.name(), connectorConfig.listenPort());
return ssl.createSslContextFactory();
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FixedHTTP2ServerConnectionFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FixedHTTP2ServerConnectionFactory.java
new file mode 100644
index 00000000000..cd82a3b2ff6
--- /dev/null
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/FixedHTTP2ServerConnectionFactory.java
@@ -0,0 +1,122 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.jdisc.http.server.jetty;
+
+import org.eclipse.jetty.http2.HTTP2Connection;
+import org.eclipse.jetty.http2.ISession;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.component.Dumpable;
+import org.eclipse.jetty.util.component.Graceful;
+import org.eclipse.jetty.util.component.LifeCycle;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.logging.Logger;
+
+/**
+ * Workaround for <a href="https://github.com/eclipse/jetty.project/issues/8811">eclipse/jetty.project#8811</a>.
+ *
+ * @author bjorncs
+ */
+class FixedHTTP2ServerConnectionFactory extends HTTP2ServerConnectionFactory {
+
+ private static final Logger log = Logger.getLogger(FixedHTTP2ServerConnectionFactory.class.getName());
+
+ private final HTTP2SessionContainer originalSessionContainer;
+ private final FixedHTTP2SessionContainer fixedSessionContainer;
+
+ FixedHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration config) {
+ super(config);
+ fixedSessionContainer = new FixedHTTP2SessionContainer();
+ originalSessionContainer = getBean(HTTP2SessionContainer.class);
+ removeBean(originalSessionContainer);
+ addBean(fixedSessionContainer);
+ }
+
+ @Override
+ public Connection newConnection(Connector connector, EndPoint endPoint) {
+ var conn = (HTTP2ServerConnection) super.newConnection(connector, endPoint);
+ conn.removeEventListener(originalSessionContainer);
+ conn.addEventListener(fixedSessionContainer);
+ return conn;
+ }
+
+ @ManagedObject("The container of HTTP/2 sessions")
+ private static class FixedHTTP2SessionContainer implements Connection.Listener, Graceful, Dumpable {
+
+ private final Object monitor = new Object();
+ private final Set<ISession> sessions = new HashSet<>();
+ private CompletableFuture<Void> shutdown;
+
+ @Override
+ public void onOpened(Connection conn) {
+ var session = session(conn);
+ boolean shuttingDown;
+ synchronized (monitor) {
+ sessions.add(session);
+ shuttingDown = shutdown != null;
+ }
+ log.fine(() -> "Added session %s".formatted(session));
+ LifeCycle.start(session);
+ if (shuttingDown) session.shutdown();
+ }
+
+ @Override
+ public void onClosed(Connection conn) {
+ var session = session(conn);
+ boolean removed;
+ CompletableFuture<Void> shutdown;
+ synchronized (monitor) {
+ removed = sessions.remove(session);
+ shutdown = this.shutdown != null && sessions.size() == 0 && !this.shutdown.isDone()
+ ? this.shutdown : null;
+ }
+ log.fine(() -> "Removed session %s".formatted(session));
+ if (removed) LifeCycle.stop(session);
+ if (shutdown != null) {
+ log.fine("Shutdown completed after last session removed");
+ shutdown.complete(null);
+ }
+ }
+
+ @Override
+ public void dump(Appendable out, String indent) throws IOException {
+ synchronized (monitor) { Dumpable.dumpObjects(out, indent, this, sessions); }
+ }
+
+ @Override public CompletableFuture<Void> shutdown() {
+ CompletableFuture<Void> shutdown = null;
+ ISession[] sessionsToClose = null;
+ synchronized (monitor) {
+ if (this.shutdown == null) {
+ shutdown = (this.shutdown = new CompletableFuture<>());
+ sessionsToClose = sessions.toArray(ISession[]::new);
+ }
+ }
+ if (sessionsToClose != null) {
+ log.fine("Shutdown initiated");
+ if (sessionsToClose.length > 0) {
+ for (ISession session : sessionsToClose) {
+ session.shutdown();
+ }
+ } else {
+ log.fine("Shutdown completed since no sessions");
+ shutdown.complete(null);
+ }
+ }
+ return shutdown;
+ }
+
+ @Override public boolean isShutdown() { synchronized (monitor) { return shutdown != null; } }
+
+ private static ISession session(Connection conn) { return ((HTTP2Connection)conn).getSession(); }
+ }
+}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
index ac50cbbb518..342d7ab9c4a 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HealthCheckProxyHandler.java
@@ -4,14 +4,24 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.security.SslContextBuilder;
+import com.yahoo.security.TrustAllX509TrustManager;
import com.yahoo.security.tls.TransportSecurityOptions;
import com.yahoo.security.tls.TransportSecurityUtils;
-import com.yahoo.security.TrustAllX509TrustManager;
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.ProxyProtocolClientConnectionFactory;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.DetectorConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SslConnectionFactory;
@@ -19,14 +29,6 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import javax.net.ssl.SSLContext;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.HashMap;
@@ -89,7 +91,7 @@ class HealthCheckProxyHandler extends HandlerWrapper {
Optional.ofNullable(targetConnector.getConnectionFactory(SslConnectionFactory.class))
.or(() -> Optional.ofNullable(targetConnector.getConnectionFactory(DetectorConnectionFactory.class))
.map(detectorConnFactory -> detectorConnFactory.getBean(SslConnectionFactory.class)))
- .map(connFactory -> (SslContextFactory.Server) connFactory.getSslContextFactory())
+ .map(SslConnectionFactory::getSslContextFactory)
.orElseThrow(() -> new IllegalArgumentException("Health check proxy can only target https port"));
boolean proxyProtocol = targetConnector.connectorConfig().proxyProtocol().enabled();
return new ProxyTarget(targetPort, clientTimeout,handlerTimeout, cacheExpiry, sslContextFactory, proxyProtocol);
@@ -269,13 +271,14 @@ class HealthCheckProxyHandler extends HandlerWrapper {
synchronized (this) {
if (client == null) {
int timeoutMillis = (int) clientTimeout.toMillis();
- SslContextFactory.Client clientSsl = new SslContextFactory.Client();
+ var clientSsl = new SslContextFactory.Client();
clientSsl.setHostnameVerifier((__, ___) -> true);
clientSsl.setSslContext(getSslContext(serverSsl));
- HttpClient client = new HttpClient(clientSsl);
+ var connector = new ClientConnector();
+ connector.setSslContextFactory(clientSsl);
+ HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(connector));
client.setMaxConnectionsPerDestination(4);
client.setConnectTimeout(timeoutMillis);
- client.setStopTimeout(timeoutMillis);
client.setIdleTimeout(timeoutMillis);
client.setUserAgentField(new HttpField(HttpHeader.USER_AGENT, "health-check-proxy-client"));
client.start();
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
index 9292e2024df..b4c933c1168 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestDispatch.java
@@ -12,6 +12,11 @@ import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpRequest;
+import jakarta.servlet.AsyncContext;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
@@ -20,11 +25,6 @@ import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Callback;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
index 8a298fb3268..d45a8789e4c 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactory.java
@@ -3,10 +3,10 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.service.CurrentContainer;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Utf8Appendable;
-import javax.servlet.http.HttpServletRequest;
import java.net.InetSocketAddress;
import java.net.URI;
import java.security.cert.X509Certificate;
@@ -94,6 +94,6 @@ class HttpRequestFactory {
}
private static X509Certificate[] getCertChain(HttpServletRequest servletRequest) {
- return (X509Certificate[]) servletRequest.getAttribute("javax.servlet.request.X509Certificate");
+ return (X509Certificate[]) servletRequest.getAttribute(RequestUtils.SERVLET_REQUEST_X509CERT);
}
}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
index 3fb81cb5352..81789881b68 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollector.java
@@ -4,6 +4,11 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.http.ServerConfig;
+import jakarta.servlet.AsyncEvent;
+import jakarta.servlet.AsyncListener;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.AsyncContextEvent;
@@ -11,14 +16,8 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpChannelState;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.component.Graceful;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -27,12 +26,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.ObjLongConsumer;
import java.util.stream.Collectors;
@@ -49,7 +46,7 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
static final String requestTypeAttribute = "requestType";
- private final AtomicReference<FutureCallback> shutdown = new AtomicReference<>();
+ private final Shutdown shutdown;
private final List<String> monitoringHandlerPaths;
private final List<String> searchHandlerPaths;
private final Set<String> ignoredUserAgents;
@@ -66,6 +63,10 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
this.monitoringHandlerPaths = monitoringHandlerPaths;
this.searchHandlerPaths = searchHandlerPaths;
this.ignoredUserAgents = Set.copyOf(ignoredUserAgents);
+ this.shutdown = new Shutdown(this) {
+ @Override public boolean isShutdownDone() { return inFlight.get() == 0; }
+ };
+
}
private final AsyncListener completionWatcher = new AsyncListener() {
@@ -97,7 +98,7 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
try {
Handler handler = getHandler();
- if (handler != null && shutdown.get() == null && isStarted()) {
+ if (handler != null && !shutdown.isShutdown() && isStarted()) {
handler.handle(path, baseRequest, request, response);
} else if ( ! baseRequest.isHandled()) {
baseRequest.setHandled(true);
@@ -129,14 +130,9 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
.increment());
}
long live = inFlight.decrementAndGet();
- FutureCallback shutdownCb = shutdown.get();
- if (shutdownCb != null) {
- if (flushableResponse != null) {
- flushableResponse.flushBuffer();
- }
- if (live == 0) {
- shutdownCb.succeeded();
- }
+ if (shutdown.isShutdown()) {
+ if (flushableResponse != null) flushableResponse.flushBuffer();
+ if (live == 0) shutdown.check();
}
}
@@ -162,35 +158,19 @@ class HttpResponseStatisticsCollector extends HandlerWrapper implements Graceful
@Override
protected void doStart() throws Exception {
- shutdown.set(null);
+ shutdown.cancel();
super.doStart();
}
@Override
protected void doStop() throws Exception {
+ shutdown.cancel();
super.doStop();
- FutureCallback shutdownCb = shutdown.get();
- if ( ! shutdownCb.isDone()) {
- shutdownCb.failed(new TimeoutException());
- }
}
- @Override
- public Future<Void> shutdown() {
- FutureCallback shutdownCb = new FutureCallback(false);
- shutdown.compareAndSet(null, shutdownCb);
- shutdownCb = shutdown.get();
- if (inFlight.get() == 0) {
- shutdownCb.succeeded();
- }
- return shutdownCb;
- }
+ @Override public CompletableFuture<Void> shutdown() { return shutdown.shutdown(); }
+ @Override public boolean isShutdown() { return shutdown.isShutdown(); }
- @Override
- public boolean isShutdown() {
- FutureCallback futureCallback = shutdown.get();
- return futureCallback != null && futureCallback.isDone();
- }
static class Dimensions {
final String protocol;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
index 4b4aff0a9bd..bd052f14867 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscHttpServlet.java
@@ -5,13 +5,13 @@ import com.yahoo.container.logging.AccessLogEntry;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.handler.OverloadException;
import com.yahoo.jdisc.http.HttpRequest.Method;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
-import javax.servlet.ServletException;
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
index b3069a64821..b17877cee84 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscServerConnector.java
@@ -3,16 +3,13 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
-import org.eclipse.jetty.http.HttpCompliance;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.io.ConnectionStatistics;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
-import javax.servlet.ServletRequest;
-import javax.servlet.http.HttpServletRequest;
-import java.net.Socket;
-import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -26,8 +23,6 @@ class JDiscServerConnector extends ServerConnector {
private final Metric.Context metricCtx;
private final ConnectionStatistics statistics;
private final ConnectorConfig config;
- private final boolean tcpKeepAlive;
- private final boolean tcpNoDelay;
private final Metric metric;
private final String connectorName;
private final int listenPort;
@@ -36,14 +31,13 @@ class JDiscServerConnector extends ServerConnector {
ConnectionMetricAggregator connectionMetricAggregator, ConnectionFactory... factories) {
super(server, factories);
this.config = config;
- this.tcpKeepAlive = config.tcpKeepAliveEnabled();
- this.tcpNoDelay = config.tcpNoDelay();
this.metric = metric;
this.connectorName = config.name();
this.listenPort = config.listenPort();
this.metricCtx = metric.createContext(createConnectorDimensions(listenPort, connectorName, 0));
this.statistics = new ConnectionStatistics();
+ setAcceptedTcpNoDelay(config.tcpNoDelay());
addBean(statistics);
ConnectorConfig.Throttling throttlingConfig = config.throttling();
if (throttlingConfig.enabled()) {
@@ -56,17 +50,6 @@ class JDiscServerConnector extends ServerConnector {
setAcceptQueueSize(config.acceptQueueSize());
setReuseAddress(config.reuseAddress());
setIdleTimeout((long) (config.idleTimeout() * 1000));
- addBean(HttpCompliance.RFC7230);
- }
-
- @Override
- protected void configure(final Socket socket) {
- super.configure(socket);
- try {
- socket.setKeepAlive(tcpKeepAlive);
- socket.setTcpNoDelay(tcpNoDelay);
- } catch (SocketException ignored) {
- }
}
public ConnectionStatistics getStatistics() {
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
index 2e2eb257b6a..d9a97d621ae 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
@@ -30,6 +30,7 @@ import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.StandardConstants;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
@@ -113,7 +114,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
info.setProxyProtocolVersion("v2");
}
if (connection.getEndPoint() instanceof ProxyConnectionFactory.ProxyEndPoint) {
- InetSocketAddress remoteAddress = connection.getEndPoint().getRemoteAddress();
+ var remoteAddress = connection.getEndPoint().getRemoteSocketAddress();
info.setRemoteAddress(remoteAddress);
}
});
@@ -243,7 +244,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
private long httpBytesSent = 0;
private long requests = 0;
private long responses = 0;
- private InetSocketAddress remoteAddress;
+ private SocketAddress remoteAddress;
private byte[] sslSessionId;
private String sslProtocol;
private String sslCipherSuite;
@@ -290,7 +291,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
synchronized ConnectionInfo incrementResponses() { ++this.responses; return this; }
- synchronized ConnectionInfo setRemoteAddress(InetSocketAddress remoteAddress) {
+ synchronized ConnectionInfo setRemoteAddress(SocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
@@ -354,9 +355,9 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
builder.withLocalAddress(localAddress.getHostString())
.withLocalPort(localAddress.getPort());
}
- if (remoteAddress != null) {
- builder.withRemoteAddress(remoteAddress.getHostString())
- .withRemotePort(remoteAddress.getPort());
+ if (remoteAddress instanceof InetSocketAddress isa) {
+ builder.withRemoteAddress(isa.getHostString())
+ .withRemotePort(isa.getPort());
}
if (sslProtocol != null && sslCipherSuite != null && sslSessionId != null) {
builder.withSslProtocol(sslProtocol)
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 775c903f5f8..7b723b3a48e 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -27,8 +27,6 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHttpOutputInterceptor;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.log.JavaUtilLog;
-import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import javax.management.remote.JMXServiceURL;
@@ -70,8 +68,6 @@ public class JettyHttpServer extends AbstractServerProvider {
if (connectorFactories.allComponents().isEmpty())
throw new IllegalArgumentException("No connectors configured.");
- initializeJettyLogging();
-
server = new Server();
server.setStopTimeout((long)(serverConfig.stopTimeout() * 1000.0));
server.setRequestLog(new AccessLogRequestLog(requestLog, serverConfig.accessLog()));
@@ -96,15 +92,6 @@ public class JettyHttpServer extends AbstractServerProvider {
this.metricsReporter = new ServerMetricReporter(metric, server);
}
- private static void initializeJettyLogging() {
- // Note: Jetty is logging stderr if no logger is explicitly configured
- try {
- Log.setLog(new JavaUtilLog());
- } catch (Exception e) {
- throw new RuntimeException("Unable to initialize logging framework for Jetty");
- }
- }
-
private static void setupJmx(Server server, ServerConfig serverConfig) {
if (serverConfig.jmx().enabled()) {
System.setProperty("java.rmi.server.hostname", "localhost");
@@ -152,7 +139,7 @@ public class JettyHttpServer extends AbstractServerProvider {
}
StatisticsHandler root = newGenericStatisticsHandler();
addChainToRoot(root, List.of(
- newResponseStatisticsHandler(serverCfg), newGzipHandler(serverCfg), perConnectorHandlers));
+ newResponseStatisticsHandler(serverCfg), newGzipHandler(), perConnectorHandlers));
return root;
}
@@ -253,22 +240,18 @@ public class JettyHttpServer extends AbstractServerProvider {
return statisticsHandler;
}
- private static GzipHandler newGzipHandler(ServerConfig serverConfig) {
- GzipHandler gzipHandler = new GzipHandlerWithVaryHeaderFixed();
- gzipHandler.setCompressionLevel(serverConfig.responseCompressionLevel());
- gzipHandler.setInflateBufferSize(8 * 1024);
- gzipHandler.setIncludedMethods("GET", "POST", "PUT", "PATCH");
- return gzipHandler;
- }
+ private static GzipHandler newGzipHandler() { return new GzipHandlerWithVaryHeaderFixed(); }
/** A subclass which overrides Jetty's default behavior of including user-agent in the vary field */
private static class GzipHandlerWithVaryHeaderFixed extends GzipHandler {
- @Override
- public HttpField getVaryField() {
- return GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING;
+ GzipHandlerWithVaryHeaderFixed() {
+ setInflateBufferSize(8 * 1024);
+ setIncludedMethods("GET", "POST", "PUT", "PATCH");
}
+ @Override public HttpField getVaryField() { return GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING; }
+
}
}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
index 1bc862bc787..da4de957739 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/RequestUtils.java
@@ -1,12 +1,12 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.http.server.jetty;
+import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jetty.http2.server.HTTP2ServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
-
-import javax.servlet.http.HttpServletRequest;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
/**
* @author bjorncs
@@ -15,7 +15,7 @@ public class RequestUtils {
public static final String JDISC_REQUEST_X509CERT = "jdisc.request.X509Certificate";
public static final String JDISC_REQUEST_CHAIN = "jdisc.request.chain";
public static final String JDISC_RESPONSE_CHAIN = "jdisc.response.chain";
- public static final String SERVLET_REQUEST_X509CERT = "javax.servlet.request.X509Certificate";
+ public static final String SERVLET_REQUEST_X509CERT = SecureRequestCustomizer.JAKARTA_SERVLET_REQUEST_X_509_CERTIFICATE;
// The local port as reported by servlet spec. This will be influenced by Host header and similar mechanisms.
// The request URI uses the local listen port as the URI is used for handler routing/bindings.
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
index 4b66715fcf7..d853282a5f5 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletOutputStreamWriter.java
@@ -2,9 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.handler.CompletionHandler;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
index 3703878f595..2f2c48e0b48 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletRequestReader.java
@@ -3,10 +3,10 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.handler.CompletionHandler;
import com.yahoo.jdisc.handler.ContentChannel;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Objects;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
index e90dde0e4eb..6afb55f5b13 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ServletResponseController.java
@@ -9,10 +9,10 @@ import com.yahoo.jdisc.handler.ResponseHandler;
import com.yahoo.jdisc.http.HttpHeaders;
import com.yahoo.jdisc.http.HttpResponse;
import com.yahoo.jdisc.service.BindingSetNotFoundException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.MimeTypes;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
index b420aabc598..96f0cdebd62 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/TlsClientAuthenticationEnforcer.java
@@ -3,13 +3,13 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.http.ConnectorConfig;
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
-import javax.servlet.DispatcherType;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
index ecbc451ead1..bdcc3f9e40a 100644
--- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
+++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.connector.def
@@ -28,7 +28,8 @@ reuseAddress bool default=true
# The maximum idle time for a connection, which roughly translates to the Socket.setSoTimeout(int).
idleTimeout double default=180.0
-# Whether or not to have socket keep alive turned on.
+# TODO Vespa 9 Remove
+# Has no effect since Jetty 11 upgrade
tcpKeepAliveEnabled bool default=false
# Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
diff --git a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
index f34fd523207..c15cb6b2cc4 100644
--- a/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
+++ b/container-core/src/main/resources/configdefinitions/jdisc.http.jdisc.http.server.def
@@ -4,7 +4,8 @@ namespace=jdisc.http
# Whether to enable developer mode, where stack traces etc are visible in response bodies.
developerMode bool default=false
-# The gzip compression level to use, if compression is enabled in a request.
+# TODO Vespa 9 Remove
+# Has no effect since Jetty 11 upgrade
responseCompressionLevel int default=6
# Whether the request body of POSTed forms should be removed (form parameters are available as request parameters).
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
index 1ff2783cc53..ce205b1a893 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactoryTest.java
@@ -5,6 +5,8 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.http.ConnectorConfig;
import com.yahoo.jdisc.http.ServerConfig;
import com.yahoo.jdisc.http.ssl.impl.ConfiguredSslContextFactoryProvider;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
@@ -12,8 +14,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
index 8b18c8cf09d..fdb9f2226de 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ErrorResponseContentCreatorTest.java
@@ -2,9 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
+import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
index a23a3505bcb..e4b82db5b9f 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpRequestFactoryTest.java
@@ -8,15 +8,17 @@ import com.yahoo.jdisc.Response;
import com.yahoo.jdisc.handler.RequestHandler;
import com.yahoo.jdisc.http.HttpRequest;
import com.yahoo.jdisc.service.CurrentContainer;
+import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
-import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Steinar Knutsen
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
index 165659389ec..502702ccf35 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpResponseStatisticsCollectorTest.java
@@ -2,6 +2,9 @@
package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.jdisc.http.server.jetty.HttpResponseStatisticsCollector.StatisticsEntry;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
@@ -10,6 +13,7 @@ import org.eclipse.jetty.http.MetaData.Response;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpChannelOverHttp;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.server.Request;
@@ -19,9 +23,6 @@ import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
@@ -164,8 +165,8 @@ public class HttpResponseStatisticsCollectorTest {
}
private Request testRequest(String scheme, int responseCode, String httpMethod, String path,
com.yahoo.jdisc.Request.RequestType explicitRequestType) {
- HttpChannel channel = new HttpChannel(connector, new HttpConfiguration(), null, new DummyTransport());
- MetaData.Request metaData = new MetaData.Request(httpMethod, new HttpURI(scheme + "://" + path), HttpVersion.HTTP_1_1, new HttpFields());
+ HttpChannel channel = new HttpChannelOverHttp(null, connector, new HttpConfiguration(), null, new DummyTransport());
+ MetaData.Request metaData = new MetaData.Request(httpMethod, HttpURI.build(scheme + "://" + path), HttpVersion.HTTP_1_1, HttpFields.build());
Request req = channel.getRequest();
if (explicitRequestType != null)
req.setAttribute("requestType", explicitRequestType);
@@ -192,7 +193,7 @@ public class HttpResponseStatisticsCollectorTest {
private final class DummyTransport implements HttpTransport {
@Override
- public void send(Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback) {
+ public void send(MetaData.Request request, Response response, ByteBuffer byteBuffer, boolean b, Callback callback) {
callback.succeeded();
}
@@ -202,11 +203,6 @@ public class HttpResponseStatisticsCollectorTest {
}
@Override
- public boolean isOptimizedForDirectBuffers() {
- return false;
- }
-
- @Override
public void push(MetaData.Request request) {
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
index 7cce9f2a9ff..ae1a6494acd 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerConformanceTest.java
@@ -807,6 +807,7 @@ public class HttpServerConformanceTest extends ServerProviderConformanceTest {
post.setProtocolVersion(HttpVersion.HTTP_1_1);
request = post;
}
+ request.addHeader("Connection", "close");
return executorService.submit(() -> httpClient.execute(request));
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
index 318067ac634..39b6dcdc6d5 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
@@ -186,9 +186,10 @@ public class HttpServerTest {
@Test
void requireThatServerCanEchoCompressed() throws Exception {
final JettyTestDriver driver = JettyTestDriver.newInstance(new EchoRequestHandler());
- SimpleHttpClient client = driver.newClient(true);
- client.get("/status.html")
- .expectStatusCode(is(OK));
+ try (SimpleHttpClient client = driver.newClient(true)) {
+ client.get("/status.html")
+ .expectStatusCode(is(OK));
+ }
assertTrue(driver.close());
}
@@ -532,9 +533,9 @@ public class HttpServerTest {
.withTrustStore(certificateFile)
.build();
- new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)
- .get("/dummy.html")
- .expectStatusCode(is(UNAUTHORIZED));
+ try (var c = new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)) {
+ c.get("/dummy.html").expectStatusCode(is(UNAUTHORIZED));
+ }
assertTrue(driver.close());
}
@@ -550,9 +551,9 @@ public class HttpServerTest {
.withTrustStore(certificateFile)
.build();
- new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)
- .get("/status.html")
- .expectStatusCode(is(OK));
+ try (var c = new SimpleHttpClient(trustStoreOnlyCtx, driver.server().getListenPort(), false)) {
+ c.get("/status.html").expectStatusCode(is(OK));
+ }
assertTrue(driver.close());
}
diff --git a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
index d4d6dcee957..6cd6f05933a 100644
--- a/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
+++ b/container-core/src/test/java/com/yahoo/jdisc/http/server/jetty/ProxyProtocolTest.java
@@ -12,6 +12,8 @@ import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.assertj.core.api.Assertions;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -185,14 +187,15 @@ class ProxyProtocolTest {
// Using Jetty's http client as Apache httpclient does not support the proxy-protocol v1/v2.
private static HttpClient createJettyHttpClient(Path certificateFile) throws Exception {
- SslContextFactory.Client clientSslCtxFactory = new SslContextFactory.Client();
- clientSslCtxFactory.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
- clientSslCtxFactory.setSslContext(new SslContextBuilder().withTrustStore(certificateFile).build());
-
- HttpClient client = new HttpClient(clientSslCtxFactory);
- client.setConnectTimeout(60*1000);
- client.setStopTimeout(60*1000);
- client.setIdleTimeout(60*1000);
+ var ssl = new SslContextFactory.Client();
+ ssl.setHostnameVerifier(NoopHostnameVerifier.INSTANCE);
+ ssl.setSslContext(new SslContextBuilder().withTrustStore(certificateFile).build());
+ var connector = new ClientConnector();
+ connector.setSslContextFactory(ssl);
+ HttpClient client = new HttpClient(new HttpClientTransportOverHTTP(connector));
+ int timeout = 60 * 1000;
+ client.setConnectTimeout(timeout);
+ client.setIdleTimeout(timeout);
client.start();
return client;
}
diff --git a/container-dev/pom.xml b/container-dev/pom.xml
index 0c88531a248..9bbb5591fbf 100644
--- a/container-dev/pom.xml
+++ b/container-dev/pom.xml
@@ -98,8 +98,8 @@
<!-- START JETTY embedded jars -->
<exclusion>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -111,11 +111,19 @@
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
@@ -131,7 +139,11 @@
</exclusion>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</exclusion>
<!-- END JETTY embedded jars -->
</exclusions>
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/VespaLowercasingSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/VespaLowercasingSearcher.java
index 51d06e74184..d0749630807 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/VespaLowercasingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/VespaLowercasingSearcher.java
@@ -38,9 +38,7 @@ public class VespaLowercasingSearcher extends LowercasingSearcher {
public boolean shouldLowercase(String commonPath, WordItem word, IndexFacts.Session indexFacts) {
if (word.isLowercased()) return false;
- StringBuilder sb = new StringBuilder();
- sb.append(commonPath).append(".").append(word.getIndexName());
- return indexFacts.getIndex(sb.toString()).isLowercase();
+ return indexFacts.getIndex(commonPath + "." + word.getIndexName()).isLowercase();
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
index 1203f69dd3c..76ceb60b3d5 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
@@ -132,7 +132,7 @@ public class YqlParser implements Parser {
public static final String USER_INPUT_LANGUAGE = "language";
private static final String USER_INPUT_GRAMMAR_RAW = "raw";
private static final String USER_INPUT_GRAMMAR_SEGMENT = "segment";
- private static final String USER_INPUT_GRAMMAR_WEAKAND = "weakAnd";
+ private static final Set<String> WEAKAND_GRAMMARS = Set.of("weakAnd", "tokenize");
private static final String USER_INPUT = "userInput";
private static final String USER_QUERY = "userQuery";
private static final String NON_EMPTY = "nonEmpty";
@@ -731,8 +731,9 @@ public class YqlParser implements Parser {
}
// Set grammar-specific annotations
- if (USER_INPUT_GRAMMAR_WEAKAND.equals(grammar) && item instanceof WeakAndItem weakAndItem) {
- weakAndItem.setN(getAnnotation(ast, TARGET_HITS, Integer.class, WeakAndItem.defaultN, "'targetHits' (N) for weak and"));
+ if (WEAKAND_GRAMMARS.contains(grammar) && item instanceof WeakAndItem weakAndItem) {
+ weakAndItem.setN(getAnnotation(ast, TARGET_HITS, Integer.class, WeakAndItem.defaultN,
+ "'targetHits' (N) for weak and"));
}
return item;
}
diff --git a/container-search/src/test/java/com/yahoo/search/yql/UserInputTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/UserInputTestCase.java
index 858d5a16352..d3c77d2ba66 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/UserInputTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/UserInputTestCase.java
@@ -91,9 +91,14 @@ public class UserInputTestCase {
@Test
void testUserInputSettingTargetHits() {
+ assertTargetHitsIsPropagatedInUserInput("weakAnd");
+ assertTargetHitsIsPropagatedInUserInput("tokenize");
+ }
+
+ private void assertTargetHitsIsPropagatedInUserInput(String grammar) {
URIBuilder builder = searchUri();
builder.setParameter("yql",
- "select * from sources * where {grammar: \"weakAnd\", targetHits: 17, defaultIndex: \"f\"}userInput(\"a test\")");
+ "select * from sources * where {grammar: \"" + grammar + "\", targetHits: 17, defaultIndex: \"f\"}userInput(\"a test\")");
Query query = searchAndAssertNoErrors(builder);
assertEquals("select * from sources * where ({targetNumHits: 17}weakAnd(f contains \"a\", f contains \"test\"))", query.yqlRepresentation());
WeakAndItem weakAnd = (WeakAndItem)query.getModel().getQueryTree().getRoot();
diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
index a1dad201958..c15c3b2c5ea 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
@@ -446,12 +446,6 @@ public class YqlParserTestCase {
}
@Test
- void testTokenizeGrammar() {
- Item root = parse("select foo from bar where ({grammar: \"tokenize\", targetHits: 10, defaultIndex: \"default\"}userInput(\"this is a test\"))").getRoot();
- assertEquals("WEAKAND(100) default:this default:is default:a default:test", root.toString());
- }
-
- @Test
void testAccentDropping() {
assertFalse(getRootWord("select foo from bar where baz contains " +
"( {accentDrop: false} \"colors\")").isNormalizable());
diff --git a/container-test/pom.xml b/container-test/pom.xml
index 32a64a98b9e..e0ff7f62e93 100644
--- a/container-test/pom.xml
+++ b/container-test/pom.xml
@@ -113,8 +113,8 @@
<!-- START JETTY embedded jars -->
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -126,11 +126,19 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@@ -146,7 +154,11 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
</dependency>
<!-- END JETTY embedded jars -->
</dependencies>
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 579e34c7667..cbdb6d1d05f 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -46,15 +46,6 @@ public class Flags {
private static volatile TreeMap<FlagId, FlagDefinition> flags = new TreeMap<>();
- public static final UnboundBooleanFlag ROOT_CHAIN_GRAPH = defineFeatureFlag(
- "root-chain-graph", true,
- List.of("hakonhall"), "2022-10-05", "2022-11-04",
- "Whether to run all tasks in the root task chain up to the one failing to converge (false), or " +
- "run all tasks in the root task chain whose dependencies have converged (true). And when suspending, " +
- "whether to run the tasks in sequence (false) or in reverse sequence (true).",
- "On first tick of the root chain after (re)start of host admin.",
- ZONE_ID, NODE_TYPE, HOSTNAME);
-
public static final UnboundDoubleFlag DEFAULT_TERM_WISE_LIMIT = defineDoubleFlag(
"default-term-wise-limit", 1.0,
List.of("baldersheim"), "2020-12-02", "2023-01-01",
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
index a271dfe571e..da9329747b4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
@@ -324,7 +324,7 @@ public class Nodes {
public Node deallocate(Node node, Agent agent, String reason, NestedTransaction transaction) {
if (parkOnDeallocationOf(node, agent)) {
- return park(node.hostname(), true, agent, reason, transaction);
+ return park(node.hostname(), false, agent, reason, transaction);
} else {
Node.State toState = Node.State.dirty;
if (node.state() == Node.State.parked) {
diff --git a/parent/pom.xml b/parent/pom.xml
index afec99ee8c1..29da1b59155 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -891,9 +891,9 @@
<version>${eclipse-collections.version}</version>
</dependency>
<dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
- <version>${jetty-alpn.version}</version>
+ <groupId>org.eclipse.jetty.http2</groupId>
+ <artifactId>http2-common</artifactId>
+ <version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@@ -907,32 +907,37 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-server</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-continuation</artifactId>
+ <artifactId>jetty-http</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-server</artifactId>
+ <artifactId>jetty-io</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlet</artifactId>
+ <artifactId>jetty-jmx</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlets</artifactId>
+ <artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-jmx</artifactId>
+ <artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
@@ -941,6 +946,11 @@
<version>${jetty.version}</version>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty.toolchain</groupId>
+ <artifactId>jetty-jakarta-servlet-api</artifactId>
+ <version>${jetty-servlet-api.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version> <!-- 2.3.3 has a BROKEN manifest -->
@@ -1118,8 +1128,8 @@
<felix.log.version>1.0.1</felix.log.version>
<findbugs.version>3.0.2</findbugs.version> <!-- Should be kept in sync with guava -->
<hdrhistogram.version>2.1.12</hdrhistogram.version>
- <jetty.version>9.4.49.v20220914</jetty.version>
- <jetty-alpn.version>1.1.3.v20160715</jetty-alpn.version>
+ <jetty.version>11.0.12</jetty.version>
+ <jetty-servlet-api.version>5.0.2</jetty-servlet-api.version>
<jjwt.version>0.11.2</jjwt.version>
<jna.version>5.11.0</jna.version>
<json-smart.version>2.4.8</json-smart.version>
diff --git a/screwdriver/release-java-artifacts.sh b/screwdriver/release-java-artifacts.sh
index e1f979cb746..e8e98015d39 100755
--- a/screwdriver/release-java-artifacts.sh
+++ b/screwdriver/release-java-artifacts.sh
@@ -39,7 +39,7 @@ chmod 700 $SD_SOURCE_DIR/screwdriver/deploy
chmod 600 $SD_SOURCE_DIR/screwdriver/deploy/*
# Build the Java code with the correct version set
-screwdriver/replace-vespa-version-in-poms.sh $VESPA_RELEASE .
+$SD_SOURCE_DIR/screwdriver/replace-vespa-version-in-poms.sh $VESPA_RELEASE .
# We disable javadoc for all modules not marked as public API
for MODULE in $(comm -2 -3 \
diff --git a/vespa-hadoop/pom.xml b/vespa-hadoop/pom.xml
index b497fda2aab..42ee990e727 100644
--- a/vespa-hadoop/pom.xml
+++ b/vespa-hadoop/pom.xml
@@ -23,15 +23,76 @@
<jettison.version>1.5.1</jettison.version>
<pig.version>0.16.0</pig.version>
<tomcat-jasper.version>5.5.23</tomcat-jasper.version>
+ <jetty9.version>9.4.49.v20220914</jetty9.version>
</properties>
<dependencyManagement>
+ <!-- Force 9.4.x version of transitive Jetty dependencies. Required by hadoop libraries -->
<dependencies>
- <!-- Force newer version of jetty-util (to match Jetty version of jdisc) -->
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-client</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-client</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-http</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
- <version>${jetty.version}</version>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-xml</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>jetty-websocket-api</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>jetty-websocket-client</artifactId>
+ <version>${jetty9.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>jetty-websocket-common</artifactId>
+ <version>${jetty9.version}</version>
</dependency>
<!-- Force fresh woodstox-core without security issue -->
<dependency>
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java
index 7ca98e4b9ba..11bd8815d77 100644
--- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.security.tool;
import com.yahoo.vespa.security.tool.crypto.DecryptTool;
import com.yahoo.vespa.security.tool.crypto.EncryptTool;
import com.yahoo.vespa.security.tool.crypto.KeygenTool;
+import com.yahoo.vespa.security.tool.crypto.TokenInfoTool;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
@@ -44,7 +45,7 @@ public class Main {
}
private static final List<Tool> TOOLS = List.of(
- new KeygenTool(), new EncryptTool(), new DecryptTool());
+ new KeygenTool(), new EncryptTool(), new DecryptTool(), new TokenInfoTool());
private static Optional<Tool> toolFromCliArgs(String[] args) {
if (args.length == 0) {
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/KeygenTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/KeygenTool.java
index a0b9cce710b..d7885dc6455 100644
--- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/KeygenTool.java
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/KeygenTool.java
@@ -64,8 +64,14 @@ public class KeygenTool implements Tool {
OPTIONS);
}
- private void handleExistingFileIfAny(Path filePath, boolean allowOverwrite) throws IOException {
- if (filePath.toFile().exists()) {
+ private static void verifyNotSameKeyPaths(Path privPath, Path pubPath) {
+ if (privPath.equals(pubPath)) {
+ throw new IllegalArgumentException("Private and public key output files must be different");
+ }
+ }
+
+ private static void handleExistingFileIfAny(Path filePath, boolean allowOverwrite) throws IOException {
+ if (Files.exists(filePath)) {
if (!allowOverwrite) {
throw new IllegalArgumentException(("Output file '%s' already exists. No keys written. " +
"If you want to overwrite existing files, specify --%s.")
@@ -83,6 +89,7 @@ public class KeygenTool implements Tool {
var arguments = invocation.arguments();
var privOutPath = Paths.get(CliUtils.optionOrThrow(arguments, PRIVATE_OUT_FILE_OPTION));
var pubOutPath = Paths.get(CliUtils.optionOrThrow(arguments, PUBLIC_OUT_FILE_OPTION));
+ verifyNotSameKeyPaths(privOutPath, pubOutPath);
boolean allowOverwrite = arguments.hasOption(OVERWRITE_EXISTING_OPTION);
handleExistingFileIfAny(privOutPath, allowOverwrite);
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/TokenInfoTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/TokenInfoTool.java
new file mode 100644
index 00000000000..dc597e9301f
--- /dev/null
+++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/TokenInfoTool.java
@@ -0,0 +1,56 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.security.tool.crypto;
+
+import com.yahoo.security.SealedSharedKey;
+import com.yahoo.text.StringUtilities;
+import com.yahoo.vespa.security.tool.Tool;
+import com.yahoo.vespa.security.tool.ToolDescription;
+import com.yahoo.vespa.security.tool.ToolInvocation;
+import org.apache.commons.cli.Option;
+
+import java.util.List;
+
+import static com.yahoo.security.ArrayUtils.fromUtf8Bytes;
+import static com.yahoo.security.ArrayUtils.hex;
+
+/**
+ * Tooling to dump the various components of a decryption token
+ *
+ * @author vekterli
+ */
+public class TokenInfoTool implements Tool {
+
+ private static final List<Option> OPTIONS = List.of();
+
+ @Override
+ public String name() {
+ return "token-info";
+ }
+
+ @Override
+ public ToolDescription description() {
+ return new ToolDescription(
+ "<token string>",
+ "Dumps information about the various components of a token",
+ "Note: this is a BETA tool version; its interface may be changed at any time",
+ OPTIONS);
+ }
+
+ @Override
+ public int invoke(ToolInvocation invocation) {
+ var arguments = invocation.arguments();
+ var leftoverArgs = arguments.getArgs();
+ if (leftoverArgs.length != 1) {
+ throw new IllegalArgumentException("Expected exactly 1 token string argument");
+ }
+ var token = SealedSharedKey.fromTokenString(leftoverArgs[0]);
+ var stdOut = invocation.stdOut();
+
+ stdOut.format("Version: %d\n", token.tokenVersion());
+ stdOut.format("Key ID: %s (%s)\n", StringUtilities.escape(fromUtf8Bytes(token.keyId())), hex(token.keyId()));
+ stdOut.format("HPKE enc: %s\n", hex(token.enc()));
+ stdOut.format("HPKE ciphertext: %s\n", hex(token.ciphertext()));
+
+ return 0;
+ }
+}
diff --git a/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java b/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
index a3651888441..8ba24d2cccc 100644
--- a/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
+++ b/vespaclient-java/src/test/java/com/yahoo/vespa/security/tool/CryptoToolsTest.java
@@ -72,6 +72,11 @@ public class CryptoToolsTest {
}
@Test
+ void token_info_help_printed_if_help_option_given_to_subtool() throws IOException {
+ verifyStdoutMatchesFile(List.of("token-info", "--help"), "expected-token-info-help-output.txt");
+ }
+
+ @Test
void missing_required_parameter_prints_error_message() throws IOException {
// We don't test all possible input arguments to all tools, since it'd be too closely
// bound to the order in which the implementation checks for argument presence.
@@ -108,6 +113,16 @@ public class CryptoToolsTest {
.formatted(absPathOf(pubKeyFile)));
}
+ @Test
+ void keygen_fails_if_priv_and_pub_paths_equal() throws IOException {
+ Path keyFile = pathInTemp("foo.txt");
+
+ verifyStderrEquals(List.of("keygen",
+ "--private-out-file", absPathOf(keyFile),
+ "--public-out-file", absPathOf(keyFile)),
+ "Invalid command line arguments: Private and public key output files must be different\n");
+ }
+
// ... but we'll allow it if someone enables the foot-gun option.
@Test
void keygen_allowed_if_output_file_exists_and_explicit_overwrite_option_specified() throws IOException {
@@ -214,6 +229,17 @@ public class CryptoToolsTest {
}
@Test
+ void token_info_fails_with_error_message_if_no_token_string_given() throws IOException {
+ verifyStderrEquals(List.of("token-info"),
+ "Invalid command line arguments: Expected exactly 1 token string argument\n");
+ }
+
+ @Test
+ void token_info_is_printed_to_stdout() throws IOException {
+ verifyStdoutMatchesFile(List.of("token-info", TEST_TOKEN), "expected-token-info-output.txt");
+ }
+
+ @Test
void can_end_to_end_keygen_encrypt_and_decrypt_via_files() throws IOException {
String greatSecret = "Dogs can't look up";
diff --git a/vespaclient-java/src/test/resources/expected-help-output.txt b/vespaclient-java/src/test/resources/expected-help-output.txt
index 45cf829c981..c973735ad46 100644
--- a/vespaclient-java/src/test/resources/expected-help-output.txt
+++ b/vespaclient-java/src/test/resources/expected-help-output.txt
@@ -1,4 +1,4 @@
usage: vespa-security <tool> [TOOL OPTIONS]
-Where <tool> is one of: keygen, encrypt, decrypt
+Where <tool> is one of: keygen, encrypt, decrypt, token-info
-h,--help Show help
Invoke vespa-security <tool> --help for tool-specific help
diff --git a/vespaclient-java/src/test/resources/expected-token-info-help-output.txt b/vespaclient-java/src/test/resources/expected-token-info-help-output.txt
new file mode 100644
index 00000000000..32b2085d07f
--- /dev/null
+++ b/vespaclient-java/src/test/resources/expected-token-info-help-output.txt
@@ -0,0 +1,5 @@
+usage: vespa-security token-info <token string>
+Dumps information about the various components of a token
+ -h,--help Show help
+Note: this is a BETA tool version; its interface may be changed at any
+time
diff --git a/vespaclient-java/src/test/resources/expected-token-info-output.txt b/vespaclient-java/src/test/resources/expected-token-info-output.txt
new file mode 100644
index 00000000000..f0661533765
--- /dev/null
+++ b/vespaclient-java/src/test/resources/expected-token-info-output.txt
@@ -0,0 +1,4 @@
+Version: 1
+Key ID: my key ID (6d79206b6579204944)
+HPKE enc: 02d4f1249766bf7794a16e59dcd252759de9a0a3c4916d1224e1905cfe82682e
+HPKE ciphertext: 577f2015a1494afcdc9820cb092b2358294e9699a819a551b6cd0185268aa214