Index: src/cf.data.pre =================================================================== RCS file: /cvsroot/squid/squid/src/cf.data.pre,v retrieving revision 1.105 diff -u -r1.105 cf.data.pre --- src/cf.data.pre 22 May 2006 01:28:25 -0000 1.105 +++ src/cf.data.pre 22 May 2006 14:12:28 -0000 @@ -2014,6 +2014,9 @@ concurrency=n concurrency level per process. Use 0 for simple helpers who can only process a single request at a time. cache=n result cache size, 0 is unbounded (default) + grace= Percentage remaining of TTL where a refresh of a + cached entry should be initiated without needing to + wait for a new reply. (default 0 for no grace period) protocol=3.0 Use URL-escaped strings instead of quoting FORMAT specifications @@ -2021,10 +2024,13 @@ %LOGIN Authenticated user login name %IDENT Ident user name %SRC Client IP + %SRCPORT Client source port %DST Requested host %PROTO Requested protocol %PORT Requested port %METHOD Request method + %MYADDR Squid interface address + %MYPORT Squid http_port number %PATH Requested URL-path (including query-string if any) %USER_CERT SSL User certificate in PEM format %USER_CERTCHAIN SSL User certificate chain in PEM format Index: src/client_side.c =================================================================== RCS file: /cvsroot/squid/squid/src/client_side.c,v retrieving revision 1.95 diff -u -r1.95 client_side.c --- src/client_side.c 22 May 2006 01:28:25 -0000 1.95 +++ src/client_side.c 22 May 2006 14:12:30 -0000 @@ -444,6 +444,7 @@ new_request->client_addr = old_request->client_addr; new_request->my_addr = old_request->my_addr; new_request->my_port = old_request->my_port; + new_request->client_port = old_request->client_port; new_request->flags = old_request->flags; new_request->flags.redirected = 1; if (old_request->auth_user_request) { @@ -3499,6 +3500,7 @@ request->client_addr = conn->peer.sin_addr; request->my_addr = conn->me.sin_addr; request->my_port = ntohs(conn->me.sin_port); + request->client_port = ntohs(conn->peer.sin_port); request->http_ver = http->http_ver; if (!urlCheckRequest(request) || httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) { Index: src/external_acl.c =================================================================== RCS file: /cvsroot/squid/squid/src/external_acl.c,v retrieving revision 1.17 diff -u -r1.17 external_acl.c --- src/external_acl.c 22 May 2006 01:28:30 -0000 1.17 +++ src/external_acl.c 22 May 2006 14:12:31 -0000 @@ -55,6 +55,7 @@ static char *makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data); static void external_acl_cache_delete(external_acl * def, external_acl_entry * entry); static int external_acl_entry_expired(external_acl * def, external_acl_entry * entry); +static int external_acl_grace_expired(external_acl * def, external_acl_entry * entry); static void external_acl_cache_touch(external_acl * def, external_acl_entry * entry); /******************************************************************* @@ -80,6 +81,7 @@ external_acl *next; int ttl; int negative_ttl; + int grace; char *name; external_acl_format *format; wordlist *cmdline; @@ -106,6 +108,9 @@ EXT_ACL_IDENT, #endif EXT_ACL_SRC, + EXT_ACL_SRCPORT, + EXT_ACL_MYADDR, + EXT_ACL_MYPORT, EXT_ACL_DST, EXT_ACL_PROTO, EXT_ACL_PORT, @@ -209,6 +214,8 @@ a->quote = QUOTE_METHOD_URL; } else if (strcmp(token, "quote=shell") == 0) { a->quote = QUOTE_METHOD_SHELL; + } else if (strncmp(token, "grace=", 6) == 0) { + a->grace = atoi(token + 6); } else { break; } @@ -271,6 +278,12 @@ #endif else if (strcmp(token, "%SRC") == 0) format->type = EXT_ACL_SRC; + else if (strcmp(token, "%SRCPORT") == 0) + format->type = EXT_ACL_SRCPORT; + else if (strcmp(token, "%MYADDR") == 0) + format->type = EXT_ACL_MYADDR; + else if (strcmp(token, "%MYPORT") == 0) + format->type = EXT_ACL_MYPORT; else if (strcmp(token, "%DST") == 0) format->type = EXT_ACL_DST; else if (strcmp(token, "%PROTO") == 0) @@ -333,10 +346,14 @@ storeAppendPrintf(sentry, " ttl=%d", node->ttl); if (node->negative_ttl != node->ttl) storeAppendPrintf(sentry, " negative_ttl=%d", node->negative_ttl); + if (node->grace) + storeAppendPrintf(sentry, " grace=%d", node->grace); if (node->children != DEFAULT_EXTERNAL_ACL_CHILDREN) storeAppendPrintf(sentry, " children=%d", node->children); if (node->concurrency) storeAppendPrintf(sentry, " concurrency=%d", node->concurrency); + if (node->cache_size) + storeAppendPrintf(sentry, " cache=%d", node->cache_size); for (format = node->format; format; format = format->next) { switch (format->type) { case EXT_ACL_HEADER: @@ -356,6 +373,9 @@ DUMP_EXT_ACL_TYPE(IDENT); #endif DUMP_EXT_ACL_TYPE(SRC); + DUMP_EXT_ACL_TYPE(SRCPORT); + DUMP_EXT_ACL_TYPE(MYADDR); + DUMP_EXT_ACL_TYPE(MYPORT); DUMP_EXT_ACL_TYPE(DST); DUMP_EXT_ACL_TYPE(PROTO); DUMP_EXT_ACL_TYPE(PORT); @@ -500,20 +520,22 @@ } if (!entry) { entry = hash_lookup(acl->def->cache, key); - if (entry && external_acl_entry_expired(acl->def, entry)) { - /* Expired entry, ignore */ - debug(82, 2) ("external_acl_cache_lookup: '%s' = expired\n", key); - entry = NULL; + if (!entry || external_acl_grace_expired(acl->def, entry)) { + debug(82, 2) ("aclMatchExternal: %s(\"%s\") = lookup needed\n", acl->def->name, key); + if (acl->def->helper->stats.queue_size <= acl->def->helper->n_running) { + ch->state[ACL_EXTERNAL] = ACL_LOOKUP_NEEDED; + return -1; + } else { + if (!entry) { + debug(82, 1) ("aclMatchExternal: '%s' queue overload. Request rejected '%s'.\n", acl->def->name, key); + return -1; + } else { + debug(82, 1) ("aclMatchExternal: '%s' queue overload. Using stale result. '%s'\n", acl->def->name, key); + /* Fall thru to processing below */ + } + } } } - if (!entry || entry->result == -1) { - debug(82, 2) ("aclMatchExternal: %s(\"%s\") = lookup needed\n", acl->def->name, key); - if (acl->def->helper->stats.queue_size >= acl->def->helper->n_running) - debug(82, 1) ("aclMatchExternal: '%s' queue overload. Request rejected.\n", acl->def->name); - else - ch->state[ACL_EXTERNAL] = ACL_LOOKUP_NEEDED; - return -1; - } external_acl_cache_touch(acl->def, entry); result = entry->result; external_acl_message = entry->message; @@ -591,6 +613,17 @@ case EXT_ACL_SRC: str = inet_ntoa(ch->src_addr); break; + case EXT_ACL_SRCPORT: + snprintf(buf, sizeof(buf), "%d", request->client_port); + str = buf; + break; + case EXT_ACL_MYADDR: + str = inet_ntoa(request->my_addr); + break; + case EXT_ACL_MYPORT: + snprintf(buf, sizeof(buf), "%d", request->my_port); + str = buf; + break; case EXT_ACL_DST: str = request->host; break; @@ -700,6 +733,18 @@ return 0; } +static int +external_acl_grace_expired(external_acl * def, external_acl_entry * entry) +{ + int ttl; + ttl = entry->result == 1 ? def->ttl : def->negative_ttl; + ttl = (ttl * (100 - def->grace)) / 100; + if (entry->date + ttl < squid_curtime) + return 1; + else + return 0; +} + static void free_external_acl_entry(void *data) { @@ -876,7 +921,7 @@ else external_acl_message = NULL; - if (cbdataValid(state->callback_data)) + if (state->callback && cbdataValid(state->callback_data)) state->callback(state->callback_data, entry); cbdataUnlock(state->callback_data); state->callback_data = NULL; @@ -902,6 +947,10 @@ const char *key; external_acl_entry *entry; externalAclState *state; + dlink_node *node; + externalAclState *oldstate = NULL; + int graceful = 0; + if (acl->def->require_auth) { int ti; /* Make sure the user is authenticated */ @@ -920,51 +969,66 @@ } debug(82, 2) ("externalAclLookup: lookup in '%s' for '%s'\n", def->name, key); entry = hash_lookup(def->cache, key); - state = cbdataAlloc(externalAclState); - state->def = def; - cbdataLock(state->def); - state->callback = callback; - state->callback_data = callback_data; - state->key = xstrdup(key); - cbdataLock(state->callback_data); - if (entry && !external_acl_entry_expired(def, entry)) { - if (entry->result == -1) { - /* There is a pending lookup. Hook into it */ - dlink_node *node; - for (node = def->queue.head; node; node = node->next) { - externalAclState *oldstate = node->data; - if (strcmp(state->key, oldstate->key) == 0) { - state->queue = oldstate->queue; - oldstate->queue = state; - return; - } - } - } else { - /* There is a cached valid result.. use it */ - /* This should not really happen, but what the heck.. */ - external_acl_message = entry->message; + if (entry && external_acl_entry_expired(def, entry)) + entry = NULL; + + /* Check for a pending lookup to hook into */ + for (node = def->queue.head; node; node = node->next) { + externalAclState *oldstatetmp = node->data; + if (strcmp(key, oldstatetmp->key) == 0) { + oldstate = oldstatetmp; + break; + } + } + + /* No need to refresh a already pending lookup during grace period */ + if (entry && external_acl_grace_expired(def, entry)) { + if (oldstate) { callback(callback_data, entry); - cbdataFree(state); return; + } else { + graceful = 1; } } - /* Check for queue overload */ - if (def->helper->stats.queue_size >= def->helper->n_running) { - external_acl_entry *entry = hash_lookup(def->cache, key); - debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); - if (entry) - external_acl_message = entry->message; - cbdataFree(state); + if (!graceful && entry && !external_acl_grace_expired(def, entry)) { + /* Should not really happen, but why not.. */ callback(callback_data, entry); return; } - /* Send it off to the helper */ - memBufDefInit(&buf); - memBufPrintf(&buf, "%s\n", key); - helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); - external_acl_cache_add(def, key, -1, NULL, NULL, NULL, NULL); - dlinkAdd(state, &state->list, &def->queue); - memBufClean(&buf); + /* No pending lookup found. Sumbit to helper */ + state = cbdataAlloc(externalAclState); + state->def = def; + cbdataLock(state->def); + state->key = xstrdup(key); + if (!graceful) { + state->callback = callback; + state->callback_data = callback_data; + cbdataLock(state->callback_data); + } + if (oldstate) { + /* Hook into pending lookup */ + state->queue = oldstate->queue; + oldstate->queue = state; + } else { + /* Check for queue overload */ + if (def->helper->stats.queue_size >= def->helper->n_running) { + debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); + cbdataFree(state); + callback(callback_data, entry); + return; + } + /* Send it off to the helper */ + memBufDefInit(&buf); + memBufPrintf(&buf, "%s\n", key); + helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); + dlinkAdd(state, &state->list, &def->queue); + memBufClean(&buf); + } + if (graceful) { + /* No need to wait during grace period */ + callback(callback_data, entry); + return; + } } int Index: src/structs.h =================================================================== RCS file: /cvsroot/squid/squid/src/structs.h,v retrieving revision 1.88 diff -u -r1.88 structs.h --- src/structs.h 22 May 2006 01:28:30 -0000 1.88 +++ src/structs.h 22 May 2006 14:12:32 -0000 @@ -1811,6 +1811,7 @@ struct in_addr client_addr; struct in_addr my_addr; unsigned short my_port; + unsigned short client_port; HttpHeader header; squid_off_t content_length; HierarchyLogEntry hier;