http_static: use authority in redirects 46/43146/2
authorMatus Fabian <[email protected]>
Wed, 11 Jun 2025 11:27:54 +0000 (07:27 -0400)
committerFlorin Coras <[email protected]>
Wed, 11 Jun 2025 15:45:29 +0000 (15:45 +0000)
Use authority in redirects instead of IP address of the listener.

Type: improvement

Change-Id: Id6dedcb59f4d3e9775ce74be483395ee782ac5d5
Signed-off-by: Matus Fabian <[email protected]>
extras/hs-test/http_test.go
extras/hs-test/infra/hst_suite.go
src/plugins/http_static/http_static.h
src/plugins/http_static/static_server.c

index 19f54d1..12811cb 100644 (file)
@@ -37,7 +37,8 @@ func init() {
                HttpClientGetTlsNoRespBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, HttpUnitTest,
                HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest,
                HttpClientGetRepeatTest, HttpClientPostRepeatTest, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest, HttpHeaderErrorConnectionDropTest,
-               HttpClientInvalidHeaderNameTest, HttpStaticHttp1OnlyTest, HttpTimerSessionDisable, HttpClientBodySizeTest)
+               HttpClientInvalidHeaderNameTest, HttpStaticHttp1OnlyTest, HttpTimerSessionDisable, HttpClientBodySizeTest,
+               HttpStaticRedirectTest)
        RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
                PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest,
                PromConsecutiveConnectionsTest, HttpGetTpsTlsTest, HttpPostTpsTlsTest, HttpClientGetRepeatMTTest, HttpClientPtrGetRepeatMTTest)
@@ -1111,7 +1112,7 @@ func HttpStaticPathSanitizationTest(s *NoTopoSuite) {
        defer resp.Body.Close()
        s.Log(DumpHttpResp(resp, true))
        s.AssertHttpStatus(resp, 301)
-       s.AssertHttpHeaderWithValue(resp, "Location", "http://"+s.VppAddr()+"/index.html")
+       s.AssertHttpHeaderWithValue(resp, "Location", "http://"+serverAddress+"/index.html")
 }
 
 func HttpStaticMovedTest(s *NoTopoSuite) {
@@ -1119,11 +1120,11 @@ func HttpStaticMovedTest(s *NoTopoSuite) {
        vpp.Container.Exec(false, "mkdir -p "+wwwRootPath+"/tmp.aaa")
        err := vpp.Container.CreateFile(wwwRootPath+"/tmp.aaa/index.html", "<html><body><p>Hello</p></body></html>")
        s.AssertNil(err, fmt.Sprint(err))
-       serverAddress := s.VppAddr()
-       s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/" + s.Ports.Http + " debug"))
+       serverAddress := s.VppAddr() + ":" + s.Ports.Http
+       s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + " debug"))
 
        client := NewHttpClient(defaultHttpTimeout, false)
-       req, err := http.NewRequest("GET", "http://"+serverAddress+":"+s.Ports.Http+"/tmp.aaa", nil)
+       req, err := http.NewRequest("GET", "http://"+serverAddress+"/tmp.aaa", nil)
        s.AssertNil(err, fmt.Sprint(err))
        resp, err := client.Do(req)
        s.AssertNil(err, fmt.Sprint(err))
@@ -1136,6 +1137,32 @@ func HttpStaticMovedTest(s *NoTopoSuite) {
        s.AssertHttpContentLength(resp, int64(0))
 }
 
+func HttpStaticRedirectTest(s *NoTopoSuite) {
+       vpp := s.Containers.Vpp.VppInstance
+       vpp.Container.Exec(false, "mkdir -p "+wwwRootPath)
+       err := vpp.Container.CreateFile(wwwRootPath+"/index.html", "<html><body><p>Hello</p></body></html>")
+       s.AssertNil(err, fmt.Sprint(err))
+       serverAddress := s.VppAddr() + ":" + s.Ports.Http
+       s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + " debug"))
+
+       req := "GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: test\r\n\r\n"
+
+       conn, err := net.DialTimeout("tcp", serverAddress, time.Second*30)
+       s.AssertNil(err, fmt.Sprint(err))
+       defer conn.Close()
+       err = conn.SetDeadline(time.Now().Add(time.Second * 5))
+       s.AssertNil(err, fmt.Sprint(err))
+       n, err := conn.Write([]byte(req))
+       s.AssertNil(err, fmt.Sprint(err))
+       s.AssertEqual(n, len([]rune(req)))
+       reply := make([]byte, 1024)
+       _, err = conn.Read(reply)
+       s.AssertNil(err, fmt.Sprint(err))
+       s.Log(string(reply))
+       expectedLocation := fmt.Sprintf("Location: http://example.com/index.html")
+       s.AssertContains(string(reply), expectedLocation)
+}
+
 func HttpStaticNotFoundTest(s *NoTopoSuite) {
        vpp := s.Containers.Vpp.VppInstance
        vpp.Container.Exec(false, "mkdir -p "+wwwRootPath)
@@ -1432,57 +1459,57 @@ func HttpInvalidTargetSyntaxTest(s *NoTopoSuite) {
        serverAddress := s.VppAddr() + ":" + s.Ports.Http
        s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + " url-handlers debug"))
 
-       resp, err := TcpSendReceive(serverAddress, "GET /interface|stats.json HTTP/1.1\r\n\r\n")
+       resp, err := TcpSendReceive(serverAddress, "GET /interface|stats.json HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "'|' not allowed in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /interface#stats.json HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /interface#stats.json HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "'#' not allowed in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /interface%stats.json HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /interface%stats.json HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /interface%1stats.json HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /interface%1stats.json HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /interface%Bstats.json HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /interface%Bstats.json HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /interface%stats.json%B HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /interface%stats.json%B HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target path")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose>true HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose>true HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "'>' not allowed in target query")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose%true HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose%true HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target query")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose=%1 HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /version.json?verbose=%1 HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request",
                "after '%' there must be two hex-digit characters in target query")
 
-       resp, err = TcpSendReceive(serverAddress, "GET * HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET * HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "asterisk-form is only used for a server-wide OPTIONS request")
 
-       resp, err = TcpSendReceive(serverAddress, "GET www.example.com:80 HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET www.example.com:80 HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "authority-form is only used for CONNECT requests")
 
-       resp, err = TcpSendReceive(serverAddress, "CONNECT https://www.example.com/tunnel HTTP/1.1\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "CONNECT https://www.example.com/tunnel HTTP/1.1\r\nHost: example.com\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "CONNECT requests must use authority-form only")
 }
@@ -1508,22 +1535,22 @@ func HttpInvalidContentLengthTest(s *NoTopoSuite) {
 
 func HttpContentLengthTest(s *NoTopoSuite) {
        vpp := s.Containers.Vpp.VppInstance
-       serverAddress := s.VppAddr()
-       s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + ":80 url-handlers debug max-body-size 12"))
+       serverAddress := s.VppAddr() + ":" + s.Ports.Http
+       s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + " url-handlers debug max-body-size 12"))
        ifName := s.VppIfName()
 
-       resp, err := TcpSendReceive(serverAddress+":80",
-               "POST /interface_stats.json HTTP/1.1\r\nContent-Length:4\r\n\r\n"+ifName)
+       resp, err := TcpSendReceive(serverAddress,
+               "POST /interface_stats.json HTTP/1.1\r\nHost: example.com\r\nContent-Length:4\r\n\r\n"+ifName)
        s.AssertNil(err, fmt.Sprint(err))
        validatePostInterfaceStats(s, resp)
 
-       resp, err = TcpSendReceive(serverAddress+":80",
-               "POST /interface_stats.json HTTP/1.1\r\nContent-Length:  4 \r\n\r\n"+ifName)
+       resp, err = TcpSendReceive(serverAddress,
+               "POST /interface_stats.json HTTP/1.1\r\nHost: example.com\r\nContent-Length:  4 \r\n\r\n"+ifName)
        s.AssertNil(err, fmt.Sprint(err))
        validatePostInterfaceStats(s, resp)
 
-       resp, err = TcpSendReceive(serverAddress+":80",
-               "POST /interface_stats.json HTTP/1.1\r\nContent-Length:\t\t4\r\n\r\n"+ifName)
+       resp, err = TcpSendReceive(serverAddress,
+               "POST /interface_stats.json HTTP/1.1\r\nHost: example.com\r\nContent-Length:\t\t4\r\n\r\n"+ifName)
        s.AssertNil(err, fmt.Sprint(err))
        validatePostInterfaceStats(s, resp)
 }
@@ -1532,7 +1559,7 @@ func HttpHeaderErrorConnectionDropTest(s *NoTopoSuite) {
        vpp := s.Containers.Vpp.VppInstance
        serverAddress := s.VppAddr() + ":" + s.Ports.Http
        s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + " url-handlers debug max-body-size 12"))
-       request := "POST /interface_stats.json HTTP/1.1\r\nContent-Length: 18234234\r\n\r\n" + s.VppIfName()
+       request := "POST /interface_stats.json HTTP/1.1\r\nHost: example.com\r\nContent-Length: 18234234\r\n\r\n" + s.VppIfName()
        conn, err := net.DialTimeout("tcp", serverAddress, time.Second*30)
        s.AssertNil(err, fmt.Sprint(err))
        err = conn.SetDeadline(time.Now().Add(time.Second * 10))
@@ -1602,10 +1629,6 @@ func HttpAbsoluteFormUriTest(s *NoTopoSuite) {
        resp, err := TcpSendReceive(serverAddress, "GET http://"+serverAddress+"/show/version HTTP/1.1\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 200 OK")
-
-       resp, err = TcpSendReceive(serverAddress, "GET http://"+serverAddress+":80/show/version HTTP/1.1\r\n\r\n")
-       s.AssertNil(err, fmt.Sprint(err))
-       s.AssertContains(resp, "HTTP/1.1 200 OK")
 }
 
 func HttpInvalidAuthorityFormUriTest(s *NoTopoSuite) {
@@ -1708,31 +1731,31 @@ func HttpInvalidHeadersTest(s *NoTopoSuite) {
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "Header section must end with CRLF CRLF")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser@Agent:test\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\r\nUser@Agent:test\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "'@' not allowed in field name")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser-Agent\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\r\nUser-Agent\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "incomplete field line not allowed")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\n: test\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\r\n: test\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "empty field name not allowed")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\rUser-Agent:test\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\rUser-Agent:test\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid field line end not allowed")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\nUser-Agent:test\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\nUser-Agent:test\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid field line end not allowed")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser-Agent:\r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\r\nUser-Agent:\r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "empty field value not allowed")
 
-       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser-Agent:    \r\n\r\n")
+       resp, err = TcpSendReceive(serverAddress, "GET /show/version HTTP/1.1\r\nHost:"+serverAddress+"\r\nUser-Agent:    \r\n\r\n")
        s.AssertNil(err, fmt.Sprint(err))
        s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "empty field value not allowed")
 }
index e9d0dac..bfc6b7a 100644 (file)
@@ -70,6 +70,8 @@ var reservedPorts = []string{
        "53",
        "67",
        "68",
+       "80",
+       "443",
        "500",
        "2152",
        "3784",
index 2c65df0..46c9e75 100644 (file)
@@ -47,6 +47,7 @@ typedef struct hss_session_
   u32 listener_index;
   u8 *target_path;
   u8 *target_query;
+  u8 *authority;
   http_req_method_t rt;
   /** Fully-resolved file path */
   u8 *path;
@@ -128,6 +129,24 @@ typedef hss_url_handler_rc_t (*hss_url_handler_fn) (hss_url_handler_args_t *);
 typedef void (*hss_register_url_fn) (hss_url_handler_fn, char *, int);
 typedef void (*hss_session_send_fn) (hss_url_handler_args_t *args);
 
+#define foreach_hss_listener_flags                                            \
+  _ (HTTP1_ONLY)                                                              \
+  _ (NEED_CRYPTO)
+
+typedef enum hss_listener_flags_bit_
+{
+#define _(sym) HSS_LISTENER_F_BIT_##sym,
+  foreach_hss_listener_flags
+#undef _
+} hss_listener_flags_bit_t;
+
+typedef enum hss_listener_flags_
+{
+#define _(sym) HSS_LISTENER_F_##sym = 1 << HSS_LISTENER_F_BIT_##sym,
+  foreach_hss_listener_flags
+#undef _
+} __clib_packed hss_listener_flags_t;
+
 typedef struct hss_listener_
 {
   /** Path to file hash table */
@@ -156,8 +175,7 @@ typedef struct hss_listener_
   u32 l_index;
   /** Listener session handle */
   session_handle_t session_handle;
-  /** Enable only HTTP/1.1 in TLS ALPN list */
-  u8 http1_only;
+  u8 flags;
 } hss_listener_t;
 
 /** \brief Main data structure
index f1cfbee..4015916 100644 (file)
@@ -435,12 +435,7 @@ static u32
 try_index_file (hss_listener_t *l, hss_session_t *hs, u8 *path)
 {
   hss_main_t *hsm = &hss_main;
-  u8 *port_str = 0, *redirect;
-  transport_endpoint_t endpt;
-  transport_proto_t proto;
-  int print_port = 0;
-  u16 local_port;
-  session_t *ts;
+  u8 *redirect;
   u32 plen;
 
   /* Remove the trailing space */
@@ -464,29 +459,13 @@ try_index_file (hss_listener_t *l, hss_session_t *hs, u8 *path)
    */
   vec_delete (path, vec_len (l->www_root) - 1, 0);
 
-  ts = session_get (hs->vpp_session_index, hs->thread_index);
-  session_get_endpoint (ts, &endpt, 1 /* is_local */);
-
-  local_port = clib_net_to_host_u16 (endpt.port);
-  proto = session_type_transport_proto (ts->session_type);
-
-  if ((proto == TRANSPORT_PROTO_TCP && local_port != 80) ||
-      (proto == TRANSPORT_PROTO_TLS && local_port != 443))
-    {
-      print_port = 1;
-      port_str = format (0, ":%u", (u32) local_port);
-    }
-
-  redirect =
-    format (0, "http%s://%U%s%s", proto == TRANSPORT_PROTO_TLS ? "s" : "",
-           format_ip46_address, &endpt.ip, endpt.is_ip4,
-           print_port ? port_str : (u8 *) "", path);
+  redirect = format (0, "http%s://%s%s",
+                    l->flags & HSS_LISTENER_F_NEED_CRYPTO ? "s" : "",
+                    hs->authority, path);
 
   if (hsm->debug_level > 0)
     clib_warning ("redirect: %s", redirect);
 
-  vec_free (port_str);
-
   if (hss_add_header (hs, HTTP_HEADER_LOCATION, (const char *) redirect,
                      vec_len (redirect)))
     return HTTP_STATUS_INTERNAL_ERROR;
@@ -691,6 +670,7 @@ hss_ts_rx_callback (session_t *ts)
   hs->data_len = 0;
   vec_free (hs->target_path);
   vec_free (hs->target_query);
+  vec_free (hs->authority);
   http_init_headers_ctx (&hs->resp_headers, hs->headers_buf,
                         vec_len (hs->headers_buf));
 
@@ -710,6 +690,21 @@ hss_ts_rx_callback (session_t *ts)
 
   hs->rt = msg.method_type;
 
+  /* Read authority */
+  if (msg.data.target_authority_len)
+    {
+      vec_validate (hs->authority, msg.data.target_authority_len - 1);
+      rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_authority_offset,
+                         msg.data.target_authority_len, hs->authority);
+      ASSERT (rv == msg.data.target_authority_len);
+    }
+  else
+    {
+      /* Mandatory Host header was missing in HTTP/1.1 request */
+      start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
+      vec_add1 (hs->authority, 0);
+      goto err_done;
+    }
   /* Read target path */
   if (msg.data.target_path_len)
     {
@@ -891,6 +886,7 @@ hss_ts_cleanup (session_t *s, session_cleanup_ntf_t ntf)
   hs->free_data = 0;
   vec_free (hs->headers_buf);
   vec_free (hs->path);
+  vec_free (hs->authority);
   vec_free (hs->target_path);
   vec_free (hs->target_query);
 
@@ -988,11 +984,12 @@ hss_listen (hss_listener_t *l, session_handle_t *lh)
 
   if (need_crypto)
     {
+      l->flags |= HSS_LISTENER_F_NEED_CRYPTO;
       ext_cfg = session_endpoint_add_ext_cfg (
        &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_CRYPTO,
        sizeof (transport_endpt_crypto_cfg_t));
       ext_cfg->crypto.ckpair_index = hsm->ckpair_index;
-      if (l->http1_only)
+      if (l->flags & HSS_LISTENER_F_HTTP1_ONLY)
        ext_cfg->crypto.alpn_protos[0] = TLS_ALPN_PROTO_HTTP_1_1;
     }
 
@@ -1135,7 +1132,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
   l->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE;
   l->rx_buff_thresh = HSS_DEFAULT_RX_BUFFER_THRESH;
   l->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT;
-  l->http1_only = 0;
+  l->flags = 0;
 
   /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -1182,7 +1179,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
                         &l->use_ptr_thresh))
        ;
       else if (unformat (line_input, "http1-only"))
-       l->http1_only = 1;
+       l->flags |= HSS_LISTENER_F_HTTP1_ONLY;
       else
        {
          error = clib_error_return (0, "unknown input `%U'",
@@ -1278,7 +1275,7 @@ hss_add_del_listener_command_fn (vlib_main_t *vm, unformat_input_t *input,
   l->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE;
   l->rx_buff_thresh = HSS_DEFAULT_RX_BUFFER_THRESH;
   l->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT;
-  l->http1_only = 0;
+  l->flags = 0;
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {