This patch is generated from the cerberian branch of s2_5 in squid Wed May 17 00:15:31 2006 GMT See http://devel.squid-cache.org/ Index: squid/src/HttpRequest.c diff -u squid/src/HttpRequest.c:1.7.36.4 squid/src/HttpRequest.c:1.7.80.3 --- squid/src/HttpRequest.c:1.7.36.4 Fri Mar 10 19:16:30 2006 +++ squid/src/HttpRequest.c Mon May 15 18:39:07 2006 @@ -67,6 +67,7 @@ httpHdrCcDestroy(req->cache_control); if (req->range) httpHdrRangeDestroy(req->range); + stringClean(&req->extacl_log); memFree(req, MEM_REQUEST_T); } Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.49.2.86 squid/src/cf.data.pre:1.49.2.51.2.7 --- squid/src/cf.data.pre:1.49.2.86 Sat Feb 25 19:13:57 2006 +++ squid/src/cf.data.pre Mon May 15 18:39:07 2006 @@ -1245,6 +1245,16 @@ and other system resources. DOC_END +NAME: redirect_concurrency +TYPE: int +DEFAULT: 0 +LOC: Config.redirectConcurrency +DOC_START + The number of requests each redirector helper can handle in + parallell. Defaults to 0 which indicates that the redirector + is a old-style singlethreaded redirector. +DOC_END + NAME: redirect_rewrites_host_header TYPE: onoff DEFAULT: on @@ -1555,9 +1565,11 @@ negative_ttl=n TTL for cached negative lookups (default same as ttl) - children=n Concurrency level / number of processes spawn - to service external acl lookups of this type. + children=n number of processes spawn to service external acl + lookups of this type. Note: see compatibility note below + 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) protocol=3.0 Use URL-escaped strings instead of quoting @@ -1592,8 +1604,11 @@ Defined keywords: - user= The users name (login) - error= Error description (only defined for ERR results) + user= The users name (login also understood) + message= Error message or similar used as %o in error messages + (error also understood) + log= String to be logged in access.log. Available as + %ea in logformat specifications Keyword values need to be enclosed in quotes if they may contain whitespace, or the whitespace escaped using \. Any quotes or \ Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.47.2.76 squid/src/client_side.c:1.47.2.43.2.6 --- squid/src/client_side.c:1.47.2.76 Fri Mar 10 19:16:31 2006 +++ squid/src/client_side.c Mon May 15 18:39:08 2006 @@ -388,6 +388,8 @@ old_request->body_reader_data = NULL; } new_request->content_length = old_request->content_length; + if (strBuf(old_request->extacl_log)) + new_request->log = stringDup(&old_request->extacl_log); requestUnlink(old_request); http->request = requestLink(new_request); } Index: squid/src/errorpage.c diff -u squid/src/errorpage.c:1.15.6.14 squid/src/errorpage.c:1.15.6.9.2.3 --- squid/src/errorpage.c:1.15.6.14 Fri Mar 10 19:16:31 2006 +++ squid/src/errorpage.c Mon May 15 18:39:08 2006 @@ -426,6 +426,7 @@ * L - HREF link for more info/contact x * M - Request Method x * m - Error message returned by external Auth. x + * o - Error message returned by external ACL x * p - URL port # x * P - Protocol x * R - Full HTTP Request x @@ -522,6 +523,11 @@ case 'M': p = r ? RequestMethodStr[r->method] : "[unkown method]"; break; + case 'o': + p = external_acl_message; + if (!p) + p = "[not available]"; + break; case 'p': if (r) { memBufPrintf(&mb, "%d", (int) r->port); Index: squid/src/external_acl.c diff -u squid/src/external_acl.c:1.2.4.28 squid/src/external_acl.c:1.2.4.23.2.5 --- squid/src/external_acl.c:1.2.4.28 Wed Mar 30 18:22:59 2005 +++ squid/src/external_acl.c Mon May 15 18:39:08 2006 @@ -45,8 +45,8 @@ #ifndef DEFAULT_EXTERNAL_ACL_TTL #define DEFAULT_EXTERNAL_ACL_TTL 1 * 60 * 60 #endif -#ifndef DEFAULT_EXTERNAL_ACL_CONCURRENCY -#define DEFAULT_EXTERNAL_ACL_CONCURRENCY 5 +#ifndef DEFAULT_EXTERNAL_ACL_CHILDREN +#define DEFAULT_EXTERNAL_ACL_CHILDREN 5 #endif typedef struct _external_acl_format external_acl_format; @@ -67,7 +67,8 @@ int result; time_t date; char *user; - char *error; + char *message; + char *log; external_acl *def; }; @@ -82,6 +83,7 @@ external_acl_format *format; wordlist *cmdline; int children; + int concurrency; helper *helper; hash_table *cache; dlink_list lru_list; @@ -105,6 +107,7 @@ EXT_ACL_DST, EXT_ACL_PROTO, EXT_ACL_PORT, + EXT_ACL_PATH, EXT_ACL_METHOD, EXT_ACL_HEADER, EXT_ACL_HEADER_MEMBER, @@ -167,7 +170,7 @@ a->ttl = DEFAULT_EXTERNAL_ACL_TTL; a->negative_ttl = -1; - a->children = DEFAULT_EXTERNAL_ACL_CONCURRENCY; + a->children = DEFAULT_EXTERNAL_ACL_CHILDREN; token = strtok(NULL, w_space); if (!token) @@ -185,7 +188,7 @@ } else if (strncmp(token, "children=", 9) == 0) { a->children = atoi(token + 9); } else if (strncmp(token, "concurrency=", 12) == 0) { - a->children = atoi(token + 12); + a->concurrency = atoi(token + 12); } else if (strncmp(token, "cache=", 6) == 0) { a->cache_size = atoi(token + 6); } else if (strcmp(token, "protocol=2.5") == 0) { @@ -264,6 +267,8 @@ format->type = EXT_ACL_PROTO; else if (strcmp(token, "%PORT") == 0) format->type = EXT_ACL_PORT; + else if (strcmp(token, "%PATH") == 0) + format->type = EXT_ACL_PATH; else if (strcmp(token, "%METHOD") == 0) format->type = EXT_ACL_METHOD; else { @@ -303,8 +308,10 @@ storeAppendPrintf(sentry, " ttl=%d", node->ttl); if (node->negative_ttl != node->ttl) storeAppendPrintf(sentry, " negative_ttl=%d", node->negative_ttl); - if (node->children != DEFAULT_EXTERNAL_ACL_CONCURRENCY) - storeAppendPrintf(sentry, " concurrency=%d", node->children); + if (node->children != DEFAULT_EXTERNAL_ACL_CHILDREN) + storeAppendPrintf(sentry, " children=%d", node->children); + if (node->concurrency) + storeAppendPrintf(sentry, " concurrency=%d", node->concurrency); for (format = node->format; format; format = format->next) { switch (format->type) { case EXT_ACL_HEADER: @@ -327,6 +334,7 @@ DUMP_EXT_ACL_TYPE(DST); DUMP_EXT_ACL_TYPE(PROTO); DUMP_EXT_ACL_TYPE(PORT); + DUMP_EXT_ACL_TYPE(PATH); DUMP_EXT_ACL_TYPE(METHOD); } } @@ -462,6 +470,8 @@ } external_acl_cache_touch(acl->def, entry); result = entry->result; + external_acl_message = entry->message; + debug(82, 2) ("aclMatchExternal: %s = %d\n", acl->def->name, result); /* FIXME: This should allocate it's own storage in the request. This * piggy backs on ident, and may fail if there is child proxies.. @@ -472,6 +482,8 @@ if (cbdataValid(ch->conn)) xstrncpy(ch->conn->rfc931, entry->user, USER_IDENT_SZ); } + if (entry->log) + stringReset(&ch->request->extacl_log, entry->log); return result; } @@ -544,6 +556,9 @@ snprintf(buf, sizeof(buf), "%d", request->port); str = buf; break; + case EXT_ACL_PATH: + str = strBuf(request->urlpath); + break; case EXT_ACL_METHOD: str = RequestMethodStr[request->method]; break; @@ -609,11 +624,12 @@ external_acl_entry *entry = data; safe_free(entry->hash.key); safe_free(entry->user); - safe_free(entry->error); + safe_free(entry->message); + safe_free(entry->log); } static external_acl_entry * -external_acl_cache_add(external_acl * def, const char *key, int result, char *user, char *error) +external_acl_cache_add(external_acl * def, const char *key, int result, char *user, char *message, char *log) { external_acl_entry *entry = hash_lookup(def->cache, key); debug(82, 2) ("external_acl_cache_add: Adding '%s' = %d\n", key, result); @@ -622,11 +638,14 @@ entry->date = squid_curtime; entry->result = result; safe_free(entry->user); - safe_free(entry->error); + safe_free(entry->message); + safe_free(entry->log); if (user) entry->user = xstrdup(user); - if (error) - entry->error = xstrdup(error); + if (message) + entry->message = xstrdup(message); + if (log) + entry->log = xstrdup(log); external_acl_cache_touch(def, entry); return entry; } @@ -640,8 +659,10 @@ entry->result = result; if (user) entry->user = xstrdup(user); - if (error) - entry->error = xstrdup(error); + if (message) + entry->message = xstrdup(message); + if (log) + entry->log = xstrdup(log); entry->def = def; hash_join(def->cache, &entry->hash); dlinkAdd(entry, &entry->lru, &def->lru_list); @@ -684,11 +705,7 @@ /* * The helper program receives queries on stdin, one - * per line, and must return the result on on stdout as - * OK user="Users login name" - * on success, and - * ERR error="Description of the error" - * on error (the user/error options are optional) + * per line, and must return the result on on stdout * * General result syntax: * @@ -697,7 +714,8 @@ * Keywords: * * user= The users name (login) - * error= Error description (only defined for ERR results) + * message= Message describing the reason + * log= A string to be used in access logging * * Other keywords may be added to the protocol later * @@ -717,7 +735,8 @@ char *value; char *t; char *user = NULL; - char *error = NULL; + char *message = NULL; + char *log = NULL; external_acl_entry *entry = NULL; debug(82, 2) ("externalAclHandleReply: reply=\"%s\"\n", reply); @@ -735,15 +754,21 @@ rfc1738_unescape(value); if (strcmp(token, "user") == 0) user = value; + else if (strcmp(token, "login") == 0) + user = value; else if (strcmp(token, "error") == 0) - error = value; + message = value; + else if (strcmp(token, "message") == 0) + message = value; + else if (strcmp(token, "log") == 0) + log = value; } } } dlinkDelete(&state->list, &state->def->queue); if (cbdataValid(state->def)) { if (reply) - entry = external_acl_cache_add(state->def, state->key, result, user, error); + entry = external_acl_cache_add(state->def, state->key, result, user, message, log); else { external_acl_entry *oldentry = hash_lookup(state->def->cache, state->key); if (oldentry) @@ -754,6 +779,11 @@ cbdataUnlock(state->def); state->def = NULL; + if (entry) + external_acl_message = entry->message; + else + external_acl_message = NULL; + if (cbdataValid(state->callback_data)) state->callback(state->callback_data, entry); cbdataUnlock(state->callback_data); @@ -765,6 +795,12 @@ } while (state); } +const char * +externalAclMessage(external_acl_entry * entry) +{ + return entry->message; +} + void externalAclLookup(aclCheck_t * ch, void *acl_data, EAH * callback, void *callback_data) { @@ -786,6 +822,7 @@ key = makeExternalAclKey(ch, acl); if (!key) { debug(82, 1) ("externalAclLookup: lookup in '%s', prerequisit failure\n", def->name); + external_acl_message = "MISSING REQUIRED INFORMATION"; callback(callback_data, NULL); return; } @@ -813,6 +850,7 @@ } else { /* There is a cached valid result.. use it */ /* This should not really happen, but what the heck.. */ + external_acl_message = entry->message; callback(callback_data, entry); cbdataFree(state); return; @@ -820,11 +858,10 @@ } /* Check for queue overload */ if (def->helper->stats.queue_size >= def->helper->n_running) { - int result = -1; external_acl_entry *entry = hash_lookup(def->cache, key); debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); if (entry) - result = entry->result; + external_acl_message = entry->message; cbdataFree(state); callback(callback_data, entry); return; @@ -833,7 +870,7 @@ memBufDefInit(&buf); memBufPrintf(&buf, "%s\n", key); helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); - external_acl_cache_add(def, key, -1, NULL, NULL); + external_acl_cache_add(def, key, -1, NULL, NULL, NULL); dlinkAdd(state, &state->list, &def->queue); memBufClean(&buf); } @@ -871,6 +908,7 @@ p->helper = helperCreate(p->name); p->helper->cmdline = p->cmdline; p->helper->n_to_start = p->children; + p->helper->concurrency = p->concurrency; p->helper->ipc_type = IPC_TCP_SOCKET; helperOpenServers(p->helper); } Index: squid/src/globals.h diff -u squid/src/globals.h:1.14.6.7 squid/src/globals.h:1.14.6.3.10.3 --- squid/src/globals.h:1.14.6.7 Mon Jun 13 19:15:00 2005 +++ squid/src/globals.h Mon May 15 18:39:08 2006 @@ -162,6 +162,7 @@ extern unsigned int WIN32_OS_version; /* 0 */ extern char *WIN32_OS_string; /* NULL */ #endif +extern const char *external_acl_message; /* NULL */ #if HAVE_SBRK extern void *sbrk_start; /* 0 */ #endif Index: squid/src/helper.c diff -u squid/src/helper.c:1.16.2.16 squid/src/helper.c:1.16.2.10.4.6 --- squid/src/helper.c:1.16.2.16 Fri Mar 10 19:16:31 2006 +++ squid/src/helper.c Mon May 15 18:39:08 2006 @@ -106,9 +106,11 @@ srv->index = k; srv->rfd = rfd; srv->wfd = wfd; - srv->buf = memAllocate(MEM_8K_BUF); - srv->buf_sz = 8192; - srv->offset = 0; + /* XXX srv->rbuf should really be a memAllocBuf(), but thisis 2.5.. */ + srv->rbuf = memAllocate(MEM_8K_BUF); + srv->rbuf_sz = 8192; + srv->roffset = 0; + srv->requests = xcalloc(hlp->concurrency ? hlp->concurrency : 1, sizeof(*srv->requests)); srv->parent = hlp; cbdataLock(hlp); /* lock because of the parent backlink */ dlinkAddTail(srv, &srv->link, &hlp->servers); @@ -336,9 +338,7 @@ void helperStats(StoreEntry * sentry, helper * hlp) { - helper_server *srv; dlink_node *link; - double tt; storeAppendPrintf(sentry, "program: %s\n", hlp->cmdline->key); storeAppendPrintf(sentry, "number running: %d of %d\n", @@ -352,30 +352,32 @@ storeAppendPrintf(sentry, "avg service time: %.2f msec\n", (double) hlp->stats.avg_svc_time / 1000.0); storeAppendPrintf(sentry, "\n"); - storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\n", + storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%9s\t%s\t%7s\t%7s\t%7s\n", "#", "FD", "PID", "# Requests", + "# Pending", "Flags", "Time", "Offset", "Request"); for (link = hlp->servers.head; link; link = link->next) { - srv = link->data; - tt = 0.001 * tvSubMsec(srv->dispatch_time, - srv->flags.busy ? current_time : srv->answer_time); - storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%c%c%c\t%7.3f\t%7d\t%s\n", + helper_server *srv = link->data; + double tt = srv->requests[0] ? 0.001 * + tvSubMsec(srv->requests[0]->dispatch_time, current_time) : 0.0; + storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%9d\t%c%c%c\t%7.3f\t%7d\t%s\n", srv->index + 1, srv->rfd, srv->pid, srv->stats.uses, - srv->flags.busy ? 'B' : ' ', + srv->stats.pending, + srv->stats.pending ? 'B' : ' ', srv->flags.closing ? 'C' : ' ', srv->flags.shutdown ? 'S' : ' ', tt < 0.0 ? 0.0 : tt, - srv->offset, - srv->request ? log_quote(srv->request->buf) : "(none)"); + srv->roffset, + srv->requests[0] ? log_quote(srv->requests[0]->buf) : "(none)"); } storeAppendPrintf(sentry, "\nFlags key:\n\n"); storeAppendPrintf(sentry, " B = BUSY\n"); @@ -450,12 +452,17 @@ hlp->n_active--; assert(hlp->n_active >= 0); srv->flags.shutdown = 1; /* request it to shut itself down */ + if (srv->flags.writing) { + debug(84, 3) ("helperShutdown: %s #%d is BUSY.\n", + hlp->id_name, srv->index + 1); + continue; + } if (srv->flags.closing) { debug(84, 3) ("helperShutdown: %s #%d is CLOSING.\n", hlp->id_name, srv->index + 1); continue; } - if (srv->flags.busy) { + if (srv->stats.pending) { debug(84, 3) ("helperShutdown: %s #%d is BUSY.\n", hlp->id_name, srv->index + 1); continue; @@ -463,7 +470,10 @@ srv->flags.closing = 1; wfd = srv->wfd; srv->wfd = -1; - comm_close(wfd); + if (wfd == srv->rfd) + shutdown(wfd, 1); + else + comm_close(wfd); } } @@ -561,17 +571,26 @@ helper_server *srv = data; helper *hlp = srv->parent; helper_request *r; + int i, concurrency = hlp->concurrency; + if (!concurrency) + concurrency = 1; assert(srv->rfd == fd); - if (srv->buf) { - memFree(srv->buf, MEM_8K_BUF); - srv->buf = NULL; - } - if ((r = srv->request)) { - if (cbdataValid(r->data)) - r->callback(r->data, srv->buf); - helperRequestFree(r); - srv->request = NULL; + if (srv->rbuf) { + /* XXX srv->rbuf should really be a memAllocBuf(), but thisis 2.5.. */ + memFree(srv->rbuf, MEM_8K_BUF); + srv->rbuf = NULL; + } + if (!memBufIsNull(&srv->wqueue)) + memBufClean(&srv->wqueue); + for (i = 0; i < concurrency; i++) { + if ((r = srv->requests[i])) { + if (cbdataValid(r->data)) + r->callback(r->data, NULL); + helperRequestFree(r); + srv->requests[i] = NULL; + } } + safe_free(srv->requests); if (srv->wfd != srv->rfd && srv->wfd != -1) comm_close(srv->wfd); dlinkDelete(&srv->link, &hlp->servers); @@ -643,54 +662,78 @@ int len; char *t = NULL; helper_server *srv = data; - helper_request *r; helper *hlp = srv->parent; assert(fd == srv->rfd); assert(cbdataValid(data)); statCounter.syscalls.sock.reads++; - len = FD_READ_METHOD(fd, srv->buf + srv->offset, srv->buf_sz - srv->offset); + /* XXX srv->rbuf should really be a memAllocBuf(), but thisis 2.5.. */ + assert(srv->roffset < srv->rbuf_sz); + len = FD_READ_METHOD(fd, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1); fd_bytes(fd, len, FD_READ); debug(84, 5) ("helperHandleRead: %d bytes from %s #%d.\n", len, hlp->id_name, srv->index + 1); - if (len <= 0) { - if (len < 0) - debug(84, 1) ("helperHandleRead: FD %d read: %s\n", fd, xstrerror()); + if (len == 0) { comm_close(fd); return; } - commSetSelect(srv->rfd, COMM_SELECT_READ, helperHandleRead, srv, 0); - srv->offset += len; - srv->buf[srv->offset] = '\0'; - r = srv->request; - if (r == NULL) { + commSetSelect(fd, COMM_SELECT_READ, helperHandleRead, srv, 0); + if (len < 0) { + if (!ignoreErrno(errno)) { + debug(84, 1) ("helperHandleRead: FD %d read: %s\n", fd, xstrerror()); + comm_close(fd); + } + return; + } + srv->roffset += len; + srv->rbuf[srv->roffset] = '\0'; + debug(84, 9) ("helperHandleRead: '%s'\n", srv->rbuf); + if (!srv->stats.pending) { /* someone spoke without being spoken to */ - debug(84, 1) ("helperHandleRead: unexpected read from %s #%d, %d bytes\n", - hlp->id_name, srv->index + 1, len); - srv->offset = 0; - } else if ((t = strchr(srv->buf, '\n'))) { + debug(84, 1) ("helperHandleRead: unexpected read from %s #%d, %d bytes '%s'\n", + hlp->id_name, srv->index + 1, len, srv->rbuf); + srv->roffset = 0; + srv->rbuf[0] = '\0'; + } + while ((t = strchr(srv->rbuf, '\n'))) { + helper_request *r; + char *msg = srv->rbuf; + int i = 0; /* end of reply found */ - debug(84, 3) ("helperHandleRead: end of reply found\n"); - *t = '\0'; - srv->flags.busy = 0; - srv->offset = 0; - srv->request = NULL; - hlp->stats.replies++; - srv->answer_time = current_time; - hlp->stats.avg_svc_time = - intAverage(hlp->stats.avg_svc_time, - tvSubUsec(srv->dispatch_time, current_time), - hlp->stats.replies, REDIRECT_AV_FACTOR); - if (cbdataValid(r->data)) - r->callback(r->data, srv->buf); - helperRequestFree(r); - if (!srv->flags.shutdown) { - helperKickQueue(hlp); - } else if (!srv->flags.closing) { + *t++ = '\0'; + debug(84, 3) ("helperHandleRead: end of reply found: %s\n", srv->rbuf); + if (hlp->concurrency) { + i = strtol(msg, &msg, 10); + while (*msg && isspace(*msg)) + msg++; + } + r = srv->requests[i]; + if (r) { + srv->requests[i] = NULL; + if (cbdataValid(r->data)) + r->callback(r->data, msg); + srv->stats.pending--; + hlp->stats.replies++; + hlp->stats.avg_svc_time = + intAverage(hlp->stats.avg_svc_time, + tvSubUsec(r->dispatch_time, current_time), + hlp->stats.replies, REDIRECT_AV_FACTOR); + helperRequestFree(r); + } else { + debug(84, 1) ("helperHandleRead: unexpected reply on channel %d from %s #%d '%s'\n", + i, hlp->id_name, srv->index + 1, srv->rbuf); + } + srv->roffset -= (t - srv->rbuf); + memmove(srv->rbuf, t, srv->roffset + 1); + } + if (srv->flags.shutdown && !srv->stats.pending) { + if (!srv->flags.closing) { int wfd = srv->wfd; srv->flags.closing = 1; srv->wfd = -1; comm_close(wfd); } + } else { + helperKickQueue(hlp); } } @@ -826,18 +869,34 @@ GetFirstAvailable(helper * hlp) { dlink_node *n; - helper_server *srv = NULL; + helper_server *srv; + helper_server *selected = NULL; if (hlp->n_running == 0) return NULL; + /* Find "least" loaded helper (approx) */ for (n = hlp->servers.head; n != NULL; n = n->next) { srv = n->data; - if (srv->flags.busy) + if (selected && selected->stats.pending <= srv->stats.pending) continue; if (srv->flags.shutdown) continue; - return srv; + if (srv->flags.shutdown) + continue; + if (selected) { + selected = srv; + break; + } + selected = srv; + if (!selected->stats.pending) + break; } - return NULL; + /* Check for overload */ + if (!selected) + return NULL; + if (selected->stats.pending >= (hlp->concurrency ? hlp->concurrency : 1)) + return NULL; + + return selected; } static helper_stateful_server * @@ -866,24 +925,78 @@ static void +helperDispatch_done(int fd, char *buf, size_t size, int status, void *data) +{ + helper_server *srv = data; + if (status != COMM_OK) { + /* Helper server has crashed.. */ + debug(84, 0) ("ERROR: Helper on fd %d has crashed!\n", fd); + } else if (!memBufIsNull(&srv->wqueue)) { + MemBuf mb = srv->wqueue; + srv->wqueue = MemBufNull; + comm_write_mbuf(srv->wfd, + mb, + helperDispatch_done, /* Handler */ + srv); + } else { + helper *hlp = srv->parent; + srv->flags.writing = 0; /* done */ + if (srv->flags.shutdown) { + int wfd; + debug(84, 3) ("helperDispatch: %s #%d is shutting down.\n", + hlp->id_name, srv->index + 1); + if (srv->flags.closing) { + debug(84, 3) ("helperDispatch: %s #%d is CLOSING.\n", + hlp->id_name, srv->index + 1); + return; + } + srv->flags.closing = 1; + wfd = srv->wfd; + srv->wfd = -1; + if (wfd == srv->rfd) + shutdown(wfd, 1); + else + comm_close(wfd); + } + } +} + +static void helperDispatch(helper_server * srv, helper_request * r) { helper *hlp = srv->parent; + helper_request **ptr = NULL; + int slot; if (!cbdataValid(r->data)) { debug(84, 1) ("helperDispatch: invalid callback data\n"); helperRequestFree(r); return; } - assert(!srv->flags.busy); - srv->flags.busy = 1; - srv->request = r; - srv->dispatch_time = current_time; - comm_write(srv->wfd, - r->buf, - strlen(r->buf), - NULL, /* Handler */ - NULL, /* Handler-data */ - NULL); /* free */ + for (slot = 0; slot < (hlp->concurrency ? hlp->concurrency : 1); slot++) { + if (!srv->requests[slot]) { + ptr = &srv->requests[slot]; + break; + } + } + assert(ptr); + *ptr = r; + srv->stats.pending += 1; + r->dispatch_time = current_time; + if (memBufIsNull(&srv->wqueue)) + memBufDefInit(&srv->wqueue); + if (hlp->concurrency) + memBufPrintf(&srv->wqueue, "%d %s", slot, r->buf); + else + memBufAppend(&srv->wqueue, r->buf, strlen(r->buf)); + if (!srv->flags.writing) { + MemBuf mb = srv->wqueue; + srv->wqueue = MemBufNull; + srv->flags.writing = 1; + comm_write_mbuf(srv->wfd, + mb, + helperDispatch_done, /* Handler */ + srv); + } debug(84, 5) ("helperDispatch: Request sent to %s #%d, %d bytes\n", hlp->id_name, srv->index + 1, (int) strlen(r->buf)); srv->stats.uses++; Index: squid/src/protos.h diff -u squid/src/protos.h:1.41.6.34 squid/src/protos.h:1.41.6.17.2.7 --- squid/src/protos.h:1.41.6.34 Sat Feb 25 19:13:57 2006 +++ squid/src/protos.h Mon May 15 18:39:09 2006 @@ -1340,5 +1340,7 @@ extern void externalAclShutdown(void); extern int externalAclRequiresAuth(void *acl_data); extern char *strtokFile(void); +const char *externalAclMessage(external_acl_entry * entry); + #endif /* SQUID_PROTOS_H */ Index: squid/src/redirect.c diff -u squid/src/redirect.c:1.7.52.3 squid/src/redirect.c:1.7.52.3.2.1 --- squid/src/redirect.c:1.7.52.3 Sun Dec 14 19:13:47 2003 +++ squid/src/redirect.c Sat Jan 17 17:09:40 2004 @@ -141,6 +141,7 @@ redirectors = helperCreate("redirector"); redirectors->cmdline = Config.Program.redirect; redirectors->n_to_start = Config.redirectChildren; + redirectors->concurrency = Config.redirectConcurrency; redirectors->ipc_type = IPC_TCP_SOCKET; helperOpenServers(redirectors); if (!init) { Index: squid/src/structs.h diff -u squid/src/structs.h:1.48.2.46 squid/src/structs.h:1.48.2.20.2.8 --- squid/src/structs.h:1.48.2.46 Fri Mar 10 19:16:31 2006 +++ squid/src/structs.h Mon May 15 18:39:09 2006 @@ -501,6 +501,7 @@ int dnsChildren; #endif int redirectChildren; + int redirectConcurrency; time_t authenticateGCInterval; time_t authenticateTTL; time_t authenticateIpTTL; @@ -1687,6 +1688,8 @@ const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */ BODY_HANDLER *body_reader; void *body_reader_data; +#define HAVE_EXTACL_LOG 1 + String extacl_log; /* String to be used for access.log purposes */ }; struct _cachemgr_passwd { @@ -2040,12 +2043,14 @@ char *buf; HLPCB *callback; void *data; + struct timeval dispatch_time; }; struct _helper_stateful_request { char *buf; HLPSCB *callback; void *data; + struct timeval dispatch_time; }; @@ -2058,6 +2063,7 @@ int n_running; int n_active; int ipc_type; + int concurrency; time_t last_queue_warn; struct { int requests; @@ -2078,6 +2084,7 @@ int n_running; int n_active; int ipc_type; + int concurrency; MemPool *datapool; HLPSAVAIL *IsAvailable; HLPSRESET *Reset; @@ -2097,21 +2104,21 @@ int pid; int rfd; int wfd; - char *buf; - size_t buf_sz; - int offset; - struct timeval dispatch_time; - struct timeval answer_time; + MemBuf wqueue; + char *rbuf; + size_t rbuf_sz; + int roffset; dlink_node link; helper *parent; - helper_request *request; + helper_request **requests; struct _helper_flags { - unsigned int busy:1; + unsigned int writing:1; unsigned int closing:1; unsigned int shutdown:1; } flags; struct { int uses; + unsigned int pending; } stats; };