From 93fd1548eeff11266bc885d097e51ef37f25c04d Mon Sep 17 00:00:00 2001 From: Blake Matheny Date: Tue, 31 Jul 2012 14:31:29 -0400 Subject: [PATCH] Adding support for item_size_max --- src/nc_conf.c | 11 +++++++++++ src/nc_conf.h | 2 ++ src/nc_message.c | 1 + src/nc_message.h | 1 + src/nc_parse.c | 23 +++++++++++++---------- src/nc_request.c | 15 +++++++++++++++ src/nc_server.h | 1 + 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/nc_conf.c b/src/nc_conf.c index e37a445b..87cd744e 100644 --- a/src/nc_conf.c +++ b/src/nc_conf.c @@ -61,6 +61,10 @@ static struct command conf_commands[] = { conf_set_num, offsetof(struct conf_pool, backlog) }, + { string("item_size_max"), + conf_set_num, + offsetof(struct conf_pool, item_size_max) }, + { string("client_connections"), conf_set_num, offsetof(struct conf_pool, client_connections) }, @@ -169,6 +173,7 @@ conf_pool_init(struct conf_pool *cp, struct string *name) cp->distribution = CONF_UNSET_DIST; cp->timeout = CONF_UNSET_NUM; cp->backlog = CONF_UNSET_NUM; + cp->item_size_max = CONF_UNSET_NUM; cp->client_connections = CONF_UNSET_NUM; @@ -256,6 +261,7 @@ conf_pool_each_transform(void *elem, void *data) sp->key_hash = hash_algos[cp->hash]; sp->timeout = cp->timeout; sp->backlog = cp->backlog; + sp->item_size_max = (uint32_t)cp->item_size_max; sp->client_connections = (uint32_t)cp->client_connections; @@ -300,6 +306,7 @@ conf_dump(struct conf *cf) log_debug(LOG_VVERB, " hash: %d", cp->hash); log_debug(LOG_VVERB, " timeout: %d", cp->timeout); log_debug(LOG_VVERB, " backlog: %d", cp->backlog); + log_debug(LOG_VVERB, " item_size_max: %d", cp->item_size_max); log_debug(LOG_VVERB, " distribution: %d", cp->distribution); log_debug(LOG_VVERB, " client_connections: %d", cp->client_connections); @@ -1186,6 +1193,10 @@ conf_validate_pool(struct conf *cf, struct conf_pool *cp) cp->backlog = CONF_DEFAULT_LISTEN_BACKLOG; } + if (cp->item_size_max == CONF_UNSET_NUM) { + cp->item_size_max = CONF_DEFAULT_ITEM_SIZE_MAX; + } + cp->client_connections = CONF_DEFAULT_CLIENT_CONNECTIONS; if (cp->preconnect == CONF_UNSET_NUM) { diff --git a/src/nc_conf.h b/src/nc_conf.h index 04a16dae..8318ee16 100644 --- a/src/nc_conf.h +++ b/src/nc_conf.h @@ -45,6 +45,7 @@ #define CONF_DEFAULT_DIST DIST_KETAMA #define CONF_DEFAULT_TIMEOUT -1 #define CONF_DEFAULT_LISTEN_BACKLOG 512 +#define CONF_DEFAULT_ITEM_SIZE_MAX 1048576 /* in bytes */ #define CONF_DEFAULT_CLIENT_CONNECTIONS 0 #define CONF_DEFAULT_PRECONNECT false #define CONF_DEFAULT_AUTO_EJECT_HOSTS false @@ -76,6 +77,7 @@ struct conf_pool { dist_type_t distribution; /* distribution: */ int timeout; /* timeout: */ int backlog; /* backlog: */ + int item_size_max; /* item_size_max: */ int client_connections; /* client_connections: */ int preconnect; /* preconnect: */ int auto_eject_hosts; /* auto_eject_hosts: */ diff --git a/src/nc_message.c b/src/nc_message.c index ca20be00..980f4583 100644 --- a/src/nc_message.c +++ b/src/nc_message.c @@ -224,6 +224,7 @@ _msg_get(void) msg->key_start = NULL; msg->key_end = NULL; msg->vlen = 0; + msg->vlen_rem = 0; msg->end = NULL; msg->frag_id = 0; diff --git a/src/nc_message.h b/src/nc_message.h index ca4a1414..a2a75101 100644 --- a/src/nc_message.h +++ b/src/nc_message.h @@ -75,6 +75,7 @@ struct msg { uint8_t *key_start; /* key start */ uint8_t *key_end; /* key end */ uint32_t vlen; /* value length */ + uint32_t vlen_rem; /* value length remaining for parse phase */ uint8_t *end; /* end marker */ uint64_t frag_id; /* id of fragmented message */ diff --git a/src/nc_parse.c b/src/nc_parse.c index b64b8ac1..30140145 100644 --- a/src/nc_parse.c +++ b/src/nc_parse.c @@ -393,7 +393,7 @@ parse_request(struct msg *r) } /* vlen_start <- p */ r->token = p; - r->vlen = (uint32_t)(ch - '0'); + r->vlen_rem = (uint32_t)(ch - '0'); state = SW_VLEN; } @@ -401,7 +401,7 @@ parse_request(struct msg *r) case SW_VLEN: if (ch >= '0' && ch <= '9') { - r->vlen = r->vlen * 10 + (uint32_t)(ch - '0'); + r->vlen_rem = r->vlen_rem * 10 + (uint32_t)(ch - '0'); } else if (r->cas) { if (ch != ' ') { goto error; @@ -409,11 +409,13 @@ parse_request(struct msg *r) /* vlen_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ r->token = NULL; + r->vlen = r->vlen_rem; state = SW_SPACES_BEFORE_CAS; } else if (ch == ' ' || ch == CR) { /* vlen_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ r->token = NULL; + r->vlen = r->vlen_rem; state = SW_RUNTO_CRLF; } else { goto error; @@ -463,10 +465,10 @@ parse_request(struct msg *r) break; case SW_VAL: - m = p + r->vlen; + m = p + r->vlen_rem; if (m >= b->last) { - ASSERT(r->vlen >= (uint32_t)(b->last - p)); - r->vlen -= (uint32_t)(b->last - p); + ASSERT(r->vlen_rem >= (uint32_t)(b->last - p)); + r->vlen_rem -= (uint32_t)(b->last - p); m = b->last - 1; p = m; /* move forward by vlen bytes */ break; @@ -932,7 +934,7 @@ parse_response(struct msg *r) } /* vlen_start <- p */ r->token = p; - r->vlen = (uint32_t)(ch - '0'); + r->vlen_rem = (uint32_t)(ch - '0'); state = SW_VLEN; } @@ -940,11 +942,12 @@ parse_response(struct msg *r) case SW_VLEN: if (ch >= '0' && ch <= '9') { - r->vlen = r->vlen * 10 + (uint32_t)(ch - '0'); + r->vlen_rem = r->vlen_rem * 10 + (uint32_t)(ch - '0'); } else if (ch == ' ' || ch == CR) { /* vlen_end <- p - 1 */ p = p - 1; /* go back by 1 byte */ r->token = NULL; + r->vlen = r->vlen_rem; state = SW_RUNTO_CRLF; } else { goto error; @@ -966,10 +969,10 @@ parse_response(struct msg *r) break; case SW_VAL: - m = p + r->vlen; + m = p + r->vlen_rem; if (m >= b->last) { - ASSERT(r->vlen >= (uint32_t)(b->last - p)); - r->vlen -= (uint32_t)(b->last - p); + ASSERT(r->vlen_rem >= (uint32_t)(b->last - p)); + r->vlen_rem -= (uint32_t)(b->last - p); m = b->last - 1; p = m; /* move forward by vlen bytes */ break; diff --git a/src/nc_request.c b/src/nc_request.c index 467e0379..27025c67 100644 --- a/src/nc_request.c +++ b/src/nc_request.c @@ -357,6 +357,8 @@ req_recv_next(struct context *ctx, struct conn *conn, bool alloc) static bool req_filter(struct context *ctx, struct conn *conn, struct msg *msg) { + struct server_pool *pool = conn->owner; + ASSERT(conn->client && !conn->proxy); if (msg_empty(msg)) { @@ -381,6 +383,19 @@ req_filter(struct context *ctx, struct conn *conn, struct msg *msg) return true; } + /* Handle excessively large request payloads */ + if (msg->vlen > pool->item_size_max) { + ASSERT(conn->rmsg == NULL); + log_debug(LOG_ERR, "filter size %"PRIu32" > max %"PRIu32" req %"PRIu64" from c %d", + msg->vlen, pool->item_size_max, msg->id, conn->sd); + conn->done = 1; + req_put(msg); + return true; + } else { + log_debug(LOG_DEBUG, "filter size %"PRIu32" req %"PRIu64" from c %d", + msg->vlen, msg->id, conn->sd); + } + return false; } diff --git a/src/nc_server.h b/src/nc_server.h index 221284c6..5b428548 100644 --- a/src/nc_server.h +++ b/src/nc_server.h @@ -111,6 +111,7 @@ struct server_pool { hash_t key_hash; /* key hasher */ int timeout; /* timeout in msec */ int backlog; /* listen backlog */ + uint32_t item_size_max; /* maximum size object (bytes) */ uint32_t client_connections; /* maximum # client connection */ uint32_t server_connections; /* maximum # server connection */ int64_t server_retry_timeout; /* server retry timeout in usec */