This is an automated email from the ASF dual-hosted git repository.

pdallig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new d98351a551 [ZEPPELIN-6209] Rewrite Jetty Servername
d98351a551 is described below

commit d98351a55141c3edf0ac7093394a661d8c5f1cee
Author: Philipp Dallig <[email protected]>
AuthorDate: Wed Jul 2 16:08:27 2025 +0200

    [ZEPPELIN-6209] Rewrite Jetty Servername
    
    ### What is this PR for?
    This PR removes a hack in your Jetty configuration, which results in an 
empty header.
    This hack was mentioned also in this Jetty Issue 
https://github.com/jetty/jetty.project/issues/6592#issuecomment-897877018
    
    ### What type of PR is it?
    Bug Fix
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-6209
    
    ### Screenshots (if appropriate)
    Before:
    
![grafik](https://github.com/user-attachments/assets/3b40019f-a90f-472c-a7c2-5402bd8f726e)
    
    After with default configuration - `zeppelin.server.send.jetty.name` = true 
and `zeppelin.server.jetty.name`=`  `
    
![grafik](https://github.com/user-attachments/assets/bff206c9-163c-4410-b024-a82ace84fabe)
    
    After with `zeppelin.server.send.jetty.name` = false
    
![grafik](https://github.com/user-attachments/assets/e232a6e0-6aea-4ba6-9cc5-d2b51ff30453)
    
    After with `zeppelin.server.send.jetty.name` = true (default) and 
`zeppelin.server.jetty.name`=`ApacheZeppelin`
    
![grafik](https://github.com/user-attachments/assets/b19ef032-6841-494f-88be-00c5bf29f90c)
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? Yes
       * Previously, we returned an empty string. In my opinion this behaviour 
is very unclean, now the check is done with `StringUtils.isNotBlank()`.
    * Does this needs documentation? No
    
    
    Closes #4953 from Reamer/hackJettyname.
    
    Signed-off-by: Philipp Dallig <[email protected]>
---
 .../apache/zeppelin/server/JettyServername.java    | 45 +++++++++++++
 .../org/apache/zeppelin/server/ZeppelinServer.java |  4 +-
 .../zeppelin/server/JettyServernameTest.java       | 78 ++++++++++++++++++++++
 3 files changed, 124 insertions(+), 3 deletions(-)

diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/JettyServername.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/JettyServername.java
new file mode 100644
index 0000000000..4c1aa83b5a
--- /dev/null
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/JettyServername.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.server;
+
+import org.eclipse.jetty.server.Request;
+
+import java.util.Optional;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.server.HttpChannel;
+
+
+public class JettyServername implements HttpChannel.Listener {
+
+  private final Optional<String> servername;
+
+  public JettyServername(final ZeppelinConfiguration zConf) {
+    if (zConf.sendJettyName() && StringUtils.isNotBlank(zConf.getJettyName())) 
{
+      this.servername = Optional.of(zConf.getJettyName().strip());
+    } else {
+      this.servername = Optional.empty();
+    }
+  }
+
+  @Override
+  public void onResponseBegin(Request request) {
+    servername.ifPresent(value -> 
request.getResponse().setHeader(HttpHeader.SERVER, value));
+  }
+}
diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
index 27f926f7ec..0df928f517 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java
@@ -274,9 +274,6 @@ public class ZeppelinServer implements AutoCloseable {
      */
     try {
       jettyWebServer.start(); // Instantiates ZeppelinServer
-      if (zConf.getJettyName() != null) {
-        
org.eclipse.jetty.http.HttpGenerator.setJettyVersion(zConf.getJettyName());
-      }
     } catch (Exception e) {
       LOGGER.error("Error while running jettyServer", e);
       System.exit(-1);
@@ -430,6 +427,7 @@ public class ZeppelinServer implements AutoCloseable {
     int timeout = 1000 * 30;
     connector.setIdleTimeout(timeout);
     connector.setHost(zConf.getServerAddress());
+    connector.addBean(new JettyServername(zConf));
     connector.addBean(new JettyConnectionMetrics(Metrics.globalRegistry, 
Tags.empty()));
     server.addConnector(connector);
   }
diff --git 
a/zeppelin-server/src/test/java/org/apache/zeppelin/server/JettyServernameTest.java
 
b/zeppelin-server/src/test/java/org/apache/zeppelin/server/JettyServernameTest.java
new file mode 100644
index 0000000000..6d659870f4
--- /dev/null
+++ 
b/zeppelin-server/src/test/java/org/apache/zeppelin/server/JettyServernameTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zeppelin.server;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import org.apache.zeppelin.conf.ZeppelinConfiguration;
+import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.junit.jupiter.api.Test;
+
+class JettyServernameTest {
+  private final String headerValue = "ZeppelinApache";
+  @Test
+  void defaultConfiguration() {
+    // given
+    Request request = mock(Request.class);
+    Response response = mock(Response.class);
+    when(request.getResponse()).thenReturn(response);
+    ZeppelinConfiguration zConf = ZeppelinConfiguration.load();
+    JettyServername httpListener = new JettyServername(zConf);
+    // when
+    httpListener.onResponseBegin(request);
+    // then
+    verifyNoInteractions(response);
+  }
+
+  @Test
+  void DoNotSendServerName() {
+    // given
+    Request request = mock(Request.class);
+    Response response = mock(Response.class);
+    when(request.getResponse()).thenReturn(response);
+    ZeppelinConfiguration zConf = ZeppelinConfiguration.load();
+    zConf.setProperty(ConfVars.ZEPPELIN_SERVER_SEND_JETTY_NAME.getVarName(), 
"false");
+    zConf.setProperty(ConfVars.ZEPPELIN_SERVER_JETTY_NAME.getVarName(), 
headerValue);
+    JettyServername httpListener = new JettyServername(zConf);
+    // when
+    httpListener.onResponseBegin(request);
+    // then
+    verifyNoInteractions(response);
+  }
+
+  @Test
+  void SendServerName() {
+    // given
+    Request request = mock(Request.class);
+    Response response = mock(Response.class);
+    when(request.getResponse()).thenReturn(response);
+    ZeppelinConfiguration zConf = ZeppelinConfiguration.load();
+    zConf.setProperty(ConfVars.ZEPPELIN_SERVER_SEND_JETTY_NAME.getVarName(), 
"true");
+    zConf.setProperty(ConfVars.ZEPPELIN_SERVER_JETTY_NAME.getVarName(), 
headerValue);
+    JettyServername httpListener = new JettyServername(zConf);
+    // when
+    httpListener.onResponseBegin(request);
+    // then
+    verify(response).setHeader(HttpHeader.SERVER, headerValue);
+  }
+}

Reply via email to