diff options
-rw-r--r-- | extras/hs-test/http_test.go | 23 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.api | 38 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.c | 29 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.h | 3 | ||||
-rw-r--r-- | src/plugins/http_static/http_static_test.c | 98 | ||||
-rw-r--r-- | src/plugins/http_static/static_server.c | 27 |
6 files changed, 208 insertions, 10 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 4cbcdeb1b21..68934550b69 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -36,7 +36,7 @@ func init() { HttpClientErrRespTest, HttpClientPostFormTest, HttpClientGet128kbResponseTest, HttpClientGetResponseBodyTest, HttpClientGetNoResponseBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, HttpUnitTest, HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest, - HttpClientGetRepeat, HttpClientPostRepeat, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest) + HttpClientGetRepeat, HttpClientPostRepeat, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest, HttpHeaderErrorConnectionDropTest) RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest, PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest, PromConsecutiveConnectionsTest, HttpGetTpsTlsTest, HttpPostTpsTlsTest) @@ -1240,7 +1240,7 @@ 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")) + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug max-body-size 12")) ifName := s.VppIfName() resp, err := TcpSendReceive(serverAddress+":80", @@ -1259,6 +1259,25 @@ func HttpContentLengthTest(s *NoTopoSuite) { validatePostInterfaceStats(s, resp) } +func HttpHeaderErrorConnectionDropTest(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")) + request := "POST /interface_stats.json HTTP/1.1\r\nContent-Length: 18234234\r\n\r\n" + s.VppIfName() + conn, err := net.DialTimeout("tcp", serverAddress+":80", time.Second*30) + s.AssertNil(err, fmt.Sprint(err)) + err = conn.SetDeadline(time.Now().Add(time.Second * 10)) + s.AssertNil(err, fmt.Sprint(err)) + _, err = conn.Write([]byte(request)) + s.AssertNil(err, fmt.Sprint(err)) + reply := make([]byte, 1024) + _, err = conn.Read(reply) + s.AssertNil(err, fmt.Sprint(err)) + s.AssertContains(string(reply), "HTTP/1.1 413 Content Too Large") + check := make([]byte, 1) + _, err = conn.Read(check) + s.AssertEqual(err, io.EOF) +} func HttpMethodNotImplementedTest(s *NoTopoSuite) { vpp := s.Containers.Vpp.VppInstance serverAddress := s.VppAddr() diff --git a/src/plugins/http_static/http_static.api b/src/plugins/http_static/http_static.api index 60c0369848d..bd0cebc45d2 100644 --- a/src/plugins/http_static/http_static.api +++ b/src/plugins/http_static/http_static.api @@ -3,7 +3,7 @@ This file defines static http server control-plane API messages */ -option version = "2.3.0"; +option version = "2.4.0"; /** \brief Configure and enable the static http server @param client_index - opaque cookie to identify the sender @@ -74,3 +74,39 @@ autoreply define http_static_enable_v3 { /* The bind URI */ string uri[256]; }; + +/** \brief Configure and enable the static http server + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param fifo_size - size (in bytes) of the session FIFOs + @param cache_size_limit - size (in bytes) of the in-memory file data cache + @param max_age - how long a response is considered fresh (in seconds) + @param max_body_size - maximum size of a request body (in bytes) + @param keepalive_timeout - timeout during which client connection will stay open (in seconds) + @param prealloc_fifos - number of preallocated fifos (usually 0) + @param private_segment_size - fifo segment size (usually 0) + @param www_root - html root path + @param uri - bind URI, defaults to "tcp://0.0.0.0/80" +*/ + +autoreply define http_static_enable_v4 { + /* Client identifier, set from api_main.my_client_index */ + u32 client_index; + + /* Arbitrary context, so client can match reply to request */ + u32 context; + /* Typical options */ + u32 fifo_size; + u32 cache_size_limit; + u32 max_age [default=600]; + u32 keepalive_timeout [default=60]; + u64 max_body_size [default=8000]; + /* Unusual options */ + u32 prealloc_fifos; + u32 private_segment_size; + + /* Root of the html path */ + string www_root[256]; + /* The bind URI */ + string uri[256]; +}; diff --git a/src/plugins/http_static/http_static.c b/src/plugins/http_static/http_static.c index 464fd27e90d..7a12f37b8d3 100644 --- a/src/plugins/http_static/http_static.c +++ b/src/plugins/http_static/http_static.c @@ -67,7 +67,7 @@ hss_register_url_handler (hss_url_handler_fn fp, const char *url, static int hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, u32 private_segment_size, u8 *www_root, u8 *uri, u32 max_age, - u32 keepalive_timeout) + u32 keepalive_timeout, u64 max_body_size) { hss_main_t *hsm = &hss_main; int rv; @@ -79,6 +79,7 @@ hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, hsm->www_root = format (0, "%s%c", www_root, 0); hsm->uri = format (0, "%s%c", uri, 0); hsm->max_age = max_age; + hsm->max_body_size = max_body_size; hsm->keepalive_timeout = keepalive_timeout; if (vec_len (hsm->www_root) < 2) @@ -119,7 +120,8 @@ vl_api_http_static_enable_v2_t_handler (vl_api_http_static_enable_v2_t *mp) rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), ntohl (mp->prealloc_fifos), ntohl (mp->private_segment_size), mp->www_root, mp->uri, - ntohl (mp->max_age), HSS_DEFAULT_KEEPALIVE_TIMEOUT); + ntohl (mp->max_age), HSS_DEFAULT_KEEPALIVE_TIMEOUT, + HSS_DEFAULT_MAX_BODY_SIZE); REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V2_REPLY); } @@ -138,11 +140,32 @@ vl_api_http_static_enable_v3_t_handler (vl_api_http_static_enable_v3_t *mp) rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), ntohl (mp->prealloc_fifos), ntohl (mp->private_segment_size), mp->www_root, mp->uri, - ntohl (mp->max_age), ntohl (mp->keepalive_timeout)); + ntohl (mp->max_age), ntohl (mp->keepalive_timeout), + HSS_DEFAULT_MAX_BODY_SIZE); REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V3_REPLY); } +/* API message handler */ +static void +vl_api_http_static_enable_v4_t_handler (vl_api_http_static_enable_v4_t *mp) +{ + vl_api_http_static_enable_v4_reply_t *rmp; + hss_main_t *hsm = &hss_main; + int rv; + + mp->uri[ARRAY_LEN (mp->uri) - 1] = 0; + mp->www_root[ARRAY_LEN (mp->www_root) - 1] = 0; + + rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), + ntohl (mp->prealloc_fifos), + ntohl (mp->private_segment_size), mp->www_root, mp->uri, + ntohl (mp->max_age), ntohl (mp->keepalive_timeout), + ntohl (mp->max_body_size)); + + REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V4_REPLY); +} + #include <http_static/http_static.api.c> static clib_error_t * hss_api_init (vlib_main_t *vm) diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index 88b0002c971..e158a32dbc9 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -24,6 +24,7 @@ #include <http_static/http_cache.h> #define HSS_DEFAULT_MAX_AGE 600 +#define HSS_DEFAULT_MAX_BODY_SIZE 8192 #define HSS_DEFAULT_KEEPALIVE_TIMEOUT 60 /** @file http_static.h @@ -161,6 +162,8 @@ typedef struct u64 cache_size; /** How long a response is considered fresh (in seconds) */ u32 max_age; + /** Maximum size of a request body (in bytes) **/ + u64 max_body_size; /** Formatted max_age: "max-age=xyz" */ u8 *max_age_formatted; /** Timeout during which client connection will stay open */ diff --git a/src/plugins/http_static/http_static_test.c b/src/plugins/http_static/http_static_test.c index edb016f9e05..56487893220 100644 --- a/src/plugins/http_static/http_static_test.c +++ b/src/plugins/http_static/http_static_test.c @@ -214,6 +214,104 @@ api_http_static_enable_v3 (vat_main_t *vam) mp->private_segment_size = ntohl (private_segment_size); mp->max_age = ntohl (max_age); mp->keepalive_timeout = ntohl (keepalive_timeout); + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static int +api_http_static_enable_v4 (vat_main_t *vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_http_static_enable_v4_t *mp; + u64 tmp; + u8 *www_root = 0; + u8 *uri = 0; + u32 prealloc_fifos = 0; + u32 private_segment_size = 0; + u32 fifo_size = 8 << 10; + u32 cache_size_limit = 1 << 20; + u32 max_age = HSS_DEFAULT_MAX_AGE; + u32 keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; + u64 max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "www-root %s", &www_root)) + ; + else if (unformat (line_input, "prealloc-fifos %d", &prealloc_fifos)) + ; + else if (unformat (line_input, "private-segment-size %U", + unformat_memory_size, &tmp)) + { + if (tmp >= 0x100000000ULL) + { + errmsg ("private segment size %llu, too large", tmp); + return -99; + } + private_segment_size = (u32) tmp; + } + else if (unformat (line_input, "fifo-size %U", unformat_memory_size, + &tmp)) + { + if (tmp >= 0x100000000ULL) + { + errmsg ("fifo-size %llu, too large", tmp); + return -99; + } + fifo_size = (u32) tmp; + } + else if (unformat (line_input, "cache-size %U", unformat_memory_size, + &tmp)) + { + if (tmp < (128ULL << 10)) + { + errmsg ("cache-size must be at least 128kb"); + return -99; + } + cache_size_limit = (u32) tmp; + } + else if (unformat (line_input, "max-age %d", &max_age)) + ; + else if (unformat (line_input, "keepalive-timeout %d", + &keepalive_timeout)) + ; + else if (unformat (line_input, "uri %s", &uri)) + ; + else if (unformat (line_input, "max-body-size %llu", &max_body_size)) + ; + else + { + errmsg ("unknown input `%U'", format_unformat_error, line_input); + return -99; + } + } + + if (www_root == 0) + { + errmsg ("Must specify www-root"); + return -99; + } + + if (uri == 0) + uri = format (0, "tcp://0.0.0.0/80%c", 0); + + /* Construct the API message */ + M (HTTP_STATIC_ENABLE_V4, mp); + strncpy_s ((char *) mp->www_root, 256, (const char *) www_root, 256); + strncpy_s ((char *) mp->uri, 256, (const char *) uri, 256); + mp->fifo_size = ntohl (fifo_size); + mp->cache_size_limit = ntohl (cache_size_limit); + mp->prealloc_fifos = ntohl (prealloc_fifos); + mp->private_segment_size = ntohl (private_segment_size); + mp->max_age = ntohl (max_age); + mp->keepalive_timeout = ntohl (keepalive_timeout); + mp->max_body_size = ntohl (max_body_size); /* send it... */ S (mp); diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 7c8c65bb9bd..074416873e3 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -500,6 +500,7 @@ handle_request (hss_session_t *hs, http_req_method_t rt, u8 *target_path, static int hss_ts_rx_callback (session_t *ts) { + hss_main_t *hsm = &hss_main; hss_session_t *hs; u8 *target_path = 0, *target_query = 0, *data = 0; http_msg_t msg; @@ -522,7 +523,7 @@ hss_ts_rx_callback (session_t *ts) http_add_header (&hs->resp_headers, HTTP_HEADER_ALLOW, http_token_lit ("GET, POST")); start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED); - goto done; + goto err_done; } /* Read target path */ @@ -535,7 +536,7 @@ hss_ts_rx_callback (session_t *ts) if (http_validate_abs_path_syntax (target_path, 0)) { start_send_data (hs, HTTP_STATUS_BAD_REQUEST); - goto done; + goto err_done; } /* Target path must be a proper C-string in addition to a vector */ vec_add1 (target_path, 0); @@ -551,13 +552,24 @@ hss_ts_rx_callback (session_t *ts) if (http_validate_query_syntax (target_query, 0)) { start_send_data (hs, HTTP_STATUS_BAD_REQUEST); - goto done; + goto err_done; } } /* Read request body for POST requests */ if (msg.data.body_len && msg.method_type == HTTP_REQ_POST) { + if (msg.data.body_len > hsm->max_body_size) + { + start_send_data (hs, HTTP_STATUS_CONTENT_TOO_LARGE); + goto err_done; + } + if (svm_fifo_max_dequeue (ts->rx_fifo) - msg.data.body_offset < + msg.data.body_len) + { + start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR); + goto err_done; + } vec_validate (data, msg.data.body_len - 1); rv = svm_fifo_peek (ts->rx_fifo, msg.data.body_offset, msg.data.body_len, data); @@ -566,7 +578,10 @@ hss_ts_rx_callback (session_t *ts) /* Find and send data */ handle_request (hs, msg.method_type, target_path, target_query, data); + goto done; +err_done: + hss_session_disconnect_transport (hs); done: vec_free (target_path); vec_free (target_query); @@ -879,6 +894,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, hsm->fifo_size = 0; hsm->cache_size = 10 << 20; hsm->max_age = HSS_DEFAULT_MAX_AGE; + hsm->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; hsm->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; /* Get a line of input. */ @@ -916,6 +932,9 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, hsm->enable_url_handlers = 1; else if (unformat (line_input, "max-age %d", &hsm->max_age)) ; + else if (unformat (line_input, "max-body-size %U", unformat_memory_size, + &hsm->max_body_size)) + ; else { error = clib_error_return (0, "unknown input `%U'", @@ -979,7 +998,7 @@ VLIB_CLI_COMMAND (hss_create_command, static) = { "http static server www-root <path> [prealloc-fifos <nn>]\n" "[private-segment-size <nnMG>] [fifo-size <nbytes>] [max-age <nseconds>]\n" "[uri <uri>] [ptr-thresh <nn>] [url-handlers] [debug [nn]]\n" - "[keepalive-timeout <nn>]\n", + "[keepalive-timeout <nn>] [max-body-size <nn>]\n", .function = hss_create_command_fn, }; |