HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest,
HttpClientGetRepeatTest, HttpClientPostRepeatTest, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest, HttpHeaderErrorConnectionDropTest,
HttpClientInvalidHeaderNameTest, HttpStaticHttp1OnlyTest, HttpTimerSessionDisable, HttpClientBodySizeTest,
- HttpStaticRedirectTest)
+ HttpStaticRedirectTest, HttpClientNoPrintTest)
RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest,
PromConsecutiveConnectionsTest, HttpGetTpsTlsTest, HttpPostTpsTlsTest)
s.AssertContains(o, "200 OK")
}
+func HttpClientNoPrintTest(s *NoTopoSuite) {
+ serverAddress := s.HostAddr() + ":" + s.Ports.Http
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress)
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ s.LogHttpReq(true),
+ ghttp.VerifyRequest("GET", "/"),
+ // Bogus header just for testing
+ ghttp.RespondWith(http.StatusOK, "<html><body><p>Hello</p></body></html>", http.Header{"Content-Type": {"image/jpeg"}}),
+ ))
+ server.Start()
+ defer server.Close()
+ uri := "http://" + serverAddress
+ vpp := s.Containers.Vpp.VppInstance
+ o := vpp.Vppctl("http client verbose uri " + uri)
+
+ s.Log(o)
+ s.AssertContains(o, "* binary file, not printing!", "no warning message found!")
+ s.AssertNotContains(o, "</html>", "</html> found in the result!")
+}
+
func HttpClientGetResponseBodyTest(s *NoTopoSuite) {
response := "<body>hello world</body>"
size := len(response)
#include <vnet/session/application_interface.h>
#include <vnet/session/session.h>
#include <http/http.h>
+#include <http/http_header_names.h>
#include <http/http_content_types.h>
#include <http/http_status_codes.h>
#include <vppinfra/unix.h>
+#define foreach_hc_s_flag \
+ _ (1, IS_CLOSED) \
+ _ (2, PRINTABLE_BODY) \
+ _ (4, BODY_OVER_LIMIT)
+
+typedef enum hc_s_flag_
+{
+#define _(n, s) HC_S_FLAG_##s = n,
+ foreach_hc_s_flag
+#undef _
+} hc_s_flags;
+
typedef struct
{
u64 req_per_wrk;
u32 session_index;
clib_thread_index_t thread_index;
u64 to_recv;
- u8 is_closed;
- u8 body_over_limit;
+ u8 session_flags;
hc_stats_t stats;
u64 data_offset;
u64 body_recv;
HC_REPEAT_DONE,
} hc_cli_signal_t;
+#define mime_printable_max_len 35
+const char mime_printable[][mime_printable_max_len] = {
+ "text/\0",
+ "application/json\0",
+ "application/javascript\0",
+ "application/x-yaml\0",
+ "application/x-www-form-urlencoded\0",
+ "application/xml\0",
+ "application/x-sh\0",
+ "application/x-tex\0",
+ "application/x-javascript\0",
+ "application/x-powershell\0"
+};
static hc_main_t hc_main;
static hc_stats_t hc_stats;
int rv;
hc_session = hc_session_get (s->opaque, s->thread_index);
- hc_session->is_closed = 1;
+ hc_session->session_flags |= HC_S_FLAG_IS_CLOSED;
a->handle = session_handle (s);
a->app_index = hcm->app_index;
session_error_t session_err = 0;
int send_err = 0;
- if (hc_session->is_closed)
+ if (hc_session->session_flags & HC_S_FLAG_IS_CLOSED)
{
clib_warning ("hc_session_index[%d] is closed", s->opaque);
return -1;
hc_session->response_status =
format (0, "%U", format_http_status_code, msg.code);
+ http_header_table_t ht = HTTP_HEADER_TABLE_NULL;
+
svm_fifo_dequeue_drop (s->rx_fifo, msg.data.headers_offset);
vec_validate (hc_session->resp_headers, msg.data.headers_len - 1);
vec_set_len (hc_session->resp_headers, msg.data.headers_len);
rv = svm_fifo_dequeue (s->rx_fifo, msg.data.headers_len,
hc_session->resp_headers);
+ ht.buf = hc_session->resp_headers;
ASSERT (rv == msg.data.headers_len);
HTTP_DBG (1, (char *) format (0, "%v", hc_session->resp_headers));
msg.data.body_offset -=
msg.data.headers_len + msg.data.headers_offset;
+
+ http_build_header_table (&ht, msg);
+ const http_token_t *content_type = http_get_header (
+ &ht, http_header_name_token (HTTP_HEADER_CONTENT_TYPE));
+ if (content_type)
+ {
+ for (u8 i = 0; i < sizeof (mime_printable) /
+ (sizeof (char) * mime_printable_max_len);
+ i++)
+ {
+ u8 mime_len =
+ clib_strnlen (mime_printable[i], mime_printable_max_len);
+ if (content_type->len >= mime_len &&
+ clib_strncmp (content_type->base, mime_printable[i],
+ mime_len) == 0)
+ {
+ hc_session->session_flags |= HC_S_FLAG_PRINTABLE_BODY;
+ break;
+ }
+ }
+ }
+ ht.buf = NULL;
+ http_free_header_table (&ht);
}
if (msg.data.body_len == 0)
goto done;
}
if (msg.data.body_len > hcm->max_body_size)
- hc_session->body_over_limit = true;
+ hc_session->session_flags |= HC_S_FLAG_BODY_OVER_LIMIT;
vec_validate (hc_session->http_response,
- (hc_session->body_over_limit ? hcm->rx_fifo_size - 1 :
- msg.data.body_len - 1));
+ (hc_session->session_flags & HC_S_FLAG_BODY_OVER_LIMIT ?
+ hcm->rx_fifo_size - 1 :
+ msg.data.body_len - 1));
vec_reset_length (hc_session->http_response);
}
}
ASSERT (rv == n_deq);
- if (!hc_session->body_over_limit)
+ if (!(hc_session->session_flags & HC_S_FLAG_BODY_OVER_LIMIT))
vec_set_len (hc_session->http_response, curr + n_deq);
ASSERT (hc_session->to_recv >= rv);
hc_session->to_recv -= rv;
{
wrk = hc_worker_get (hcm->worker_index);
hc_session = hc_session_get (wrk->session_index, wrk->thread_index);
- vlib_cli_output (vm, "< %v\n< %v\n", hc_session->response_status,
+ vlib_cli_output (vm, "< %v\n< %v\n%v", hc_session->response_status,
hc_session->resp_headers);
- if (hc_session->body_over_limit)
+ if (hc_session->session_flags & HC_S_FLAG_BODY_OVER_LIMIT)
vlib_cli_output (
vm, "* message body over limit, read total %llu bytes",
hc_session->body_recv);
else
- vlib_cli_output (vm, "%v", hc_session->http_response);
+ {
+ if (hc_session->session_flags & HC_S_FLAG_PRINTABLE_BODY)
+ vlib_cli_output (vm, "%v", hc_session->http_response);
+ else
+ vlib_cli_output (vm,
+ "* binary file, not printing!\n* consider "
+ "saving to file with the 'file' option");
+ }
}
break;
case HC_REPEAT_DONE: