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)
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) {
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))
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)
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")
}
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)
}
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))
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) {
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")
}
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 */
*/
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;
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));
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)
{
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);
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;
}
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))
&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'",
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)
{