--------------------- PatchSet 5691 Date: 2003/04/04 16:53:51 Author: hno Branch: icap-2_5 Tag: (none) Log: Imported ICAP client 1.2.1 with update for Squid-2.5.STABLE2 Members: acconfig.h:1.13.2.3->1.13.2.3.6.1 configure.in:1.42.2.35->1.42.2.35.2.1 src/Makefile.am:1.13.2.8->1.13.2.8.6.1 src/cache_cf.c:1.38.6.11->1.38.6.11.2.1 src/cbdata.c:1.14->1.14.32.1 src/cf.data.pre:1.49.2.33->1.49.2.33.2.1 src/cf_gen_defines:1.5->1.5.48.1 src/client_side.c:1.47.2.28->1.47.2.28.2.1 src/comm.c:1.18.6.2->1.18.6.2.12.1 src/enums.h:1.29.2.8->1.29.2.8.2.1 src/forward.c:1.13.6.3->1.13.6.3.2.1 src/http.c:1.17.6.3->1.17.6.3.6.1 src/main.c:1.28.6.8->1.28.6.8.2.1 src/mem.c:1.13->1.13.28.1 src/mk-string-arrays.pl:1.2->1.2.140.1 src/protos.h:1.41.6.13->1.41.6.13.2.1 src/squid.h:1.13.6.6->1.13.6.6.2.1 src/structs.h:1.48.2.9->1.48.2.9.2.1 src/typedefs.h:1.25.6.1->1.25.6.1.6.1 Index: squid/acconfig.h =================================================================== RCS file: /cvsroot/squid-sf//squid/Attic/acconfig.h,v retrieving revision 1.13.2.3 retrieving revision 1.13.2.3.6.1 diff -u -r1.13.2.3 -r1.13.2.3.6.1 --- squid/acconfig.h 1 Jul 2002 17:24:48 -0000 1.13.2.3 +++ squid/acconfig.h 4 Apr 2003 16:53:51 -0000 1.13.2.3.6.1 @@ -23,7 +23,7 @@ #ifndef __CONFIGURE_H__ #define __CONFIGURE_H__ @TOP@ -/* $Id: acconfig.h,v 1.13.2.3 2002/07/01 17:24:48 squidadm Exp $ */ +/* $Id: acconfig.h,v 1.13.2.3.6.1 2003/04/04 16:53:51 hno Exp $ */ /* * configure command line used to configure Squid @@ -87,6 +87,13 @@ */ #undef DELAY_POOLS + +/* + * ICAP - Internet Content Adaptation Protocol + */ +#undef HS_FEAT_ICAP + + /* * If you want to log User-Agent request header values, define this. * By default, they are written to useragent.log in the Squid log Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.42.2.35 retrieving revision 1.42.2.35.2.1 diff -u -r1.42.2.35 -r1.42.2.35.2.1 --- squid/configure.in 18 Mar 2003 03:23:20 -0000 1.42.2.35 +++ squid/configure.in 4 Apr 2003 16:53:55 -0000 1.42.2.35.2.1 @@ -3,7 +3,7 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.42.2.35 2003/03/18 03:23:20 squidadm Exp $ +dnl $Id: configure.in,v 1.42.2.35.2.1 2003/04/04 16:53:55 hno Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AM_INIT_AUTOMAKE(squid, 2.5.STABLE2-CVS) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.42.2.35 $)dnl +AC_REVISION($Revision: 1.42.2.35.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -433,6 +433,17 @@ fi ]) +dnl Enable ICAP Support +AM_CONDITIONAL(USE_ICAP, false) +AC_ARG_ENABLE(icap-support, +[ --enable-icap-support Enable iCAP client capability], +[ if test "$enableval" = "yes" ; then + echo "ICAP support enabled" + AC_DEFINE(HS_FEAT_ICAP) + AM_CONDITIONAL(USE_ICAP, true) + fi +]) + dnl This is a developer only option. Developers know how to set defines dnl dnl AC_ARG_ENABLE(mem-gen-trace, Index: squid/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v retrieving revision 1.13.2.8 retrieving revision 1.13.2.8.6.1 diff -u -r1.13.2.8 -r1.13.2.8.6.1 --- squid/src/Makefile.am 10 Nov 2002 22:44:12 -0000 1.13.2.8 +++ squid/src/Makefile.am 4 Apr 2003 16:54:14 -0000 1.13.2.8.6.1 @@ -6,6 +6,12 @@ # Uncomment and customize the following to suit your needs: # +if USE_ICAP +ICAPSOURCE = icap.c icap_opt.c +else +ICAPSOURCE = +endif + if USE_DNSSERVER DNSSOURCE = dns.c DNSSERVER = dnsserver @@ -98,6 +104,8 @@ dnsserver.c \ dns_internal.c \ htcp.c \ + icap.c \ + icap_opt.c \ leakfinder.c \ snmp_core.c \ snmp_agent.c \ @@ -150,6 +158,7 @@ HttpMsg.c \ HttpReply.c \ HttpRequest.c \ + $(ICAPSOURCE) \ icmp.c \ icp_v2.c \ icp_v3.c \ Index: squid/src/cache_cf.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v retrieving revision 1.38.6.11 retrieving revision 1.38.6.11.2.1 diff -u -r1.38.6.11 -r1.38.6.11.2.1 --- squid/src/cache_cf.c 7 Feb 2003 03:16:11 -0000 1.38.6.11 +++ squid/src/cache_cf.c 4 Apr 2003 16:54:19 -0000 1.38.6.11.2.1 @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.c,v 1.38.6.11 2003/02/07 03:16:11 squidadm Exp $ + * $Id: cache_cf.c,v 1.38.6.11.2.1 2003/04/04 16:54:19 hno Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -2061,6 +2061,556 @@ return bodylist.head == NULL; } +#ifdef HS_FEAT_ICAP + +/*************************************************** + * prototypes + */ +static int icap_service_process(icap_service *s); +static void icap_service_init(icap_service *s); +static void icap_service_destroy(icap_service *s); +icap_service* icap_service_lookup(char *name); +static int icap_class_process(icap_class *c); +static void icap_class_destroy(icap_class *c); +static void icap_access_destroy(icap_access* a); +static void dump_wordlist(StoreEntry * entry, const char *name, wordlist * list); +static void icap_class_add(icap_class *c); + +/*************************************************** + * icap_service + */ + +/* + * example: + * icap_service reqmode_precache 0 icap://192.168.0.1:1344/respmod + */ + +static void +parse_icap_service_type(IcapConfig * cfg) +{ + icap_service *A = NULL; + icap_service *B = NULL; + icap_service **T = NULL; + + A = cbdataAlloc(icap_service); + icap_service_init(A); + parse_string(&A->name); + parse_string(&A->type_name); + parse_ushort(&A->bypass); + parse_string(&A->uri); + debug(3,5) ("parse_icap_service_type (line %d): %s %s %d %s\n", config_lineno, A->name, A->type_name, A->bypass, A->name); + + if (icap_service_process(A)) { + /* put into linked list */ + for (B = cfg->service_head, T = &cfg->service_head; B; T = &B->next, B = B->next); + *T = A; + } else { + /* clean up structure */ + debug(3,0) ("parse_icap_service_type (line %d): skipping %s\n", config_lineno, A->name); + icap_service_destroy(A); + cbdataFree(A); + } + +} + +static void +dump_icap_service_type(StoreEntry *e, const char *name, IcapConfig cfg) +{ + icap_service *current_node = NULL; + + if (!cfg.service_head) { + storeAppendPrintf(e, "%s 0\n", name); + return; + } + + current_node = cfg.service_head; + + while (current_node) { + storeAppendPrintf(e, "%s %s %s %d %s\n", name, current_node->name, current_node->type_name, current_node->bypass, current_node->uri); + current_node = current_node->next; + } + +} + +static void +free_icap_service_type(IcapConfig * cfg) +{ + icap_service *current_node = NULL; + icap_service *next_node = NULL; + if (cfg->service_head) { + current_node = cfg->service_head; + while (current_node) { + next_node = current_node->next; + icap_service_destroy(current_node); + cbdataFree(current_node); + current_node = next_node; + } + } +} + +/* + * parse the raw string and cache some parts that are needed later + * returns 1 if everything was ok + */ +static int +icap_service_process(icap_service *s) +{ + char *start, *end; + char *tailp; + unsigned int len; + int port_in_uri; + s->type = icapServiceToType(s->type_name); + if (s->type >= ICAP_SERVICE_MAX) { + debug(3,0) ("icap_service_process (line %d): wrong service type %s\n", config_lineno, s->type_name); + return 0; + } + + if (s->type == ICAP_SERVICE_REQMOD_PRECACHE || s->type == ICAP_SERVICE_REQMOD_POSTCACHE) { + s->method = ICAP_METHOD_REQMOD; + } else if(s->type == ICAP_SERVICE_RESPMOD_PRECACHE || s->type == ICAP_SERVICE_RESPMOD_POSTCACHE) { + s->method = ICAP_METHOD_RESPMOD; + } + + debug(3,5) ("icap_service_process (line %d): type=%s\n", config_lineno, icapServiceToStr(s->type)); + if (strncmp (s->uri,"icap://", 7) != 0) { + debug(3,0) ("icap_service_process (line %d): wrong uri: %s\n", config_lineno, s->uri); + return 0; + } + start = s->uri + 7; + if ((end = strchr(start, ':')) != NULL ) { + /* ok */ + port_in_uri=1; + debug(3,5) ("icap_service_process (line %d): port given\n", config_lineno); + } else if ((end = strchr(start,'/')) != NULL ) { + /* ok */ + port_in_uri=0; + debug(3,5) ("icap_service_process (line %d): no port given\n", config_lineno); + } else { + debug(3,0) ("icap_service_process (line %d): wrong service uri: %s\n", config_lineno, s->uri); + return 0; + } + len = end - start; + s->hostname = xstrndup(start, len + 1); + s->hostname[len] = 0; + start = end; + + if (port_in_uri) { + start++; /* skip ':' */ + if ((end = strchr(start, '/')) != NULL) { + s->port = strtoul(start, &tailp, 0) % 65536; + if (tailp != end) { + debug(3,0) ("icap_service_process (line %d): wrong service uri (port could not be parsed): %s\n", config_lineno, s->uri); + return 0; + } + debug(3,5) ("icap_service_process (line %d): port=%d\n", config_lineno, s->port); + start = end; + if (start[0] != '/') { + debug(3,0) ("icap_service_process (line %d): no '/' between port and resource found in %s\n", config_lineno, s->uri); + return 0; + } + } + } else { + /* no explicit ICAP port; first ask by getservbyname or default to + hardwired port 1344 per ICAP specification section 4.2 */ + struct servent *serv = getservbyname("icap", "tcp"); + if (serv) { + s->port = htons(serv->s_port); + debug(3,5) ("icap_service_process (line %d): default port=%d getservbyname(icap,tcp)\n", config_lineno, s->port); + } else { + s->port = 1344; + debug(3,5) ("icap_service_process (line %d): default hardwired port=%d\n", config_lineno, s->port); + } + } + + start++; /* skip '/' */ + /* the rest is resource name */ + end = strchr(start, '\0'); + len = end - start; + if (len > 1024) { + debug(3,0) ("icap_service_process (line %d): long resource name (>1024), probably wrong\n", config_lineno); + } + s->resource = xstrndup(start, len + 1); + s->resource[len] = 0; + /* check bypass */ + if ( (s->bypass != 0) && (s->bypass != 1)) { + debug(3,0) ("icap_service_process (line %d): invalid bypass value\n", config_lineno); + return 0; + } + return 1; +} + +/* + * constructor + */ +static void +icap_service_init(icap_service *s) +{ + s->type = ICAP_SERVICE_MAX; /* means undefined */ + s->preview = Config.icapcfg.preview_size; + s->opt = 0; + s->istag = StringNull; + s->transfer_preview = StringNull; + s->transfer_ignore = StringNull; + s->transfer_complete = StringNull; +} + +/* + * destructor + * frees only strings, but don't touch the linked list + */ +static void +icap_service_destroy(icap_service *s) +{ + xfree(s->name); + xfree(s->uri); + xfree(s->type_name); + xfree(s->hostname); + xfree(s->resource); + assert(s->opt == 0); /* there should be no opt request running now */ + stringClean(&s->istag); + stringClean(&s->transfer_preview); + stringClean(&s->transfer_ignore); + stringClean(&s->transfer_complete); +} + +icap_service * +icap_service_lookup(char *name) +{ + icap_service *iter; + for (iter = Config.icapcfg.service_head; iter; iter = iter->next) { + if (! strcmp(name, iter->name)) { + return iter; + } + } + return NULL; +} + +/*************************************************** + * icap_service_list + */ + +static void +icap_service_list_add(icap_service_list **isl, icap_service *service) +{ + icap_service_list **iter; + icap_service_list *new; + + new = memAllocate(MEM_ICAP_SERVICE_LIST); + new->service = service; + + if (*isl) { + iter = isl; + while ((*iter)->next) + iter = &((*iter)->next); + (*iter)->next = new; + } else { + *isl = new; + } +} + +/* + * free the linked list without touching references icap_service + */ +static void +icap_service_list_destroy(icap_service_list* isl) +{ + icap_service_list *current; + icap_service_list *next; + + current = isl; + while (current) { + next = current->next; + memFree(current, MEM_ICAP_SERVICE_LIST); + current = next; + } +} + +/*************************************************** + * icap_class + */ +static void +parse_icap_class_type(IcapConfig *cfg) +{ + icap_class *s = NULL; + + s = memAllocate(MEM_ICAP_CLASS); + parse_string(&s->name); + parse_wordlist(&s->services); + + if (icap_class_process(s)) { + /* if ok, put into linked list */ + icap_class_add(s); + } else { + /* clean up structure */ + debug(3,0) ("parse_icap_class_type (line %d): skipping %s\n", config_lineno, s->name); + icap_class_destroy(s); + memFree(s, MEM_ICAP_CLASS); + } +} + +static void +dump_icap_class_type(StoreEntry *e, const char *name, IcapConfig cfg) +{ + icap_class* current_node = NULL; + LOCAL_ARRAY(char, nom, 64); + + if (!cfg.class_head) { + storeAppendPrintf(e, "%s 0\n", name); + return; + } + + current_node = cfg.class_head; + + while (current_node) { + snprintf(nom, 64, "%s %s", name, current_node->name); + dump_wordlist(e, nom, current_node->services); + current_node = current_node->next; + } +} + +static void +free_icap_class_type(IcapConfig *cfg) +{ + icap_class *current_node = NULL; + icap_class *next_node = NULL; + if (cfg->class_head) { + current_node = cfg->class_head; + while (current_node) { + next_node = current_node->next; + icap_class_destroy(current_node); + memFree(current_node, MEM_ICAP_CLASS); + current_node = next_node; + } + } +} + +/* + * process services list, return 1, if at least one service was found + */ +static int +icap_class_process(icap_class *c) +{ + icap_service_list *isl = NULL; + wordlist *iter; + icap_service *service; + /* take services list and build icap_service_list from it */ + for (iter = c->services; iter; iter = iter->next) { + service = icap_service_lookup(iter->key); + if (service) { + icap_service_list_add(&isl, service); + } else { + debug(3,0) ("icap_class_process (line %d): skipping service %s in class %s\n", config_lineno, iter->key, c->name); + } + } + + if (isl) { + c->isl = isl; + return 1; + } + return 0; +} + +/* + * search for an icap_class in the global IcapConfig + * classes with hidden-flag are skipped + */ +icap_class * +icap_class_lookup(char *name) +{ + icap_class *iter; + for (iter = Config.icapcfg.class_head; iter; iter = iter->next) { + if ((!strcmp(name, iter->name)) && (!iter->hidden)) { + return iter; + } + } + return NULL; +} + +/* + * adds an icap_class to the global IcapConfig + */ +static void +icap_class_add(icap_class *c) +{ + icap_class *cp = NULL; + icap_class **t = NULL; + IcapConfig *cfg = &Config.icapcfg; + if (c) { + for (cp = cfg->class_head, t = &cfg->class_head; cp; t = &cp->next, cp = cp->next); + *t = c; + } +} + +/* + * free allocated memory inside icap_class + */ +static void +icap_class_destroy(icap_class *c) +{ + xfree(c->name); + wordlistDestroy(&c->services); + icap_service_list_destroy(c->isl); +} + +/*************************************************** + * icap_access + */ + +/* format: icap_access {allow|deny} acl, ... */ +static void +parse_icap_access_type(IcapConfig * cfg) +{ + icap_access *A = NULL; + icap_access *B = NULL; + icap_access **T = NULL; + icap_service *s = NULL; + icap_class *c = NULL; + ushort no_class = 0; + + A = memAllocate(MEM_ICAP_ACCESS); + parse_string(&A->service_name); + + /* + * try to find a class with the given name first. if not found, search + * the services. if a service is found, create a new hidden class with + * only this service. this is for backward compatibility. + * + * the special classname All is allowed only in deny rules, because + * the class is not used there. + */ + if (!strcmp(A->service_name, "None")) { + no_class = 1; + } else { + A->class = icap_class_lookup(A->service_name); + if (!A->class) { + s = icap_service_lookup(A->service_name); + if (s) { + c = memAllocate(MEM_ICAP_CLASS); + c->name = xstrdup("(hidden)"); + c->hidden = 1; + wordlistAdd(&c->services, A->service_name); + c->isl = memAllocate(MEM_ICAP_SERVICE_LIST); + c->isl->service = s; + icap_class_add(c); + A->class = c; + } else { + debug(3,0) ("parse_icap_access_type (line %d): servicename %s not found. skipping.\n", config_lineno, A->service_name); + memFree(A, MEM_ICAP_ACCESS); + return; + } + } + } + + aclParseAccessLine(&(A->access)); + debug(3,5) ("parse_icap_access_type (line %d): %s\n", config_lineno, A->service_name); + + /* check that All class is only used in deny rule */ + if (no_class && A->access->allow) { + memFree(A, MEM_ICAP_ACCESS); + debug(3,0) ("parse_icap_access (line %d): special class 'None' only allowed in deny rule. skipping.\n", config_lineno); + return; + } + + if (A->access) { + for (B = cfg->access_head, T = &cfg->access_head; B; T = &B->next, B = B->next); + *T = A; + } else { + debug(3,0) ("parse_icap_access_type (line %d): invalid line skipped\n", config_lineno); + memFree(A, MEM_ICAP_ACCESS); + } +} + +static void +dump_icap_access_type(StoreEntry *e, const char *name, IcapConfig cfg) +{ + icap_access* current_node = NULL; + LOCAL_ARRAY(char, nom, 64); + + if (!cfg.access_head) { + storeAppendPrintf(e, "%s 0\n", name); + return; + } + + current_node = cfg.access_head; + + while (current_node) { + snprintf(nom, 64, "%s %s", name, current_node->service_name); + dump_acl_access(e, nom, current_node->access); + current_node = current_node->next; + } +} + +static void +free_icap_access_type(IcapConfig * cfg) +{ + icap_access *current_node = NULL; + icap_access *next_node = NULL; + if (cfg->access_head) { + current_node = cfg->access_head; + while (current_node) { + next_node = current_node->next; + icap_access_destroy(current_node); + memFree(current_node, MEM_ICAP_ACCESS); + current_node = next_node; + } + } +} + +/* + * destructor + * frees everything but the linked list + */ +static void +icap_access_destroy(icap_access* a) +{ + xfree(a->service_name); + aclDestroyAccessList(&a->access); +} + +/*************************************************** + * for debugging purposes only + */ +void +dump_icap_config(IcapConfig* cfg) { + icap_service* s_iter; + icap_class* c_iter; + icap_access* a_iter; + icap_service_list *isl_iter; + acl_list* l; + debug(3,0)("IcapConfig: onoff = %d\n", cfg->onoff); + debug(3,0)("IcapConfig: service_head = %d\n", (int) cfg->service_head); + debug(3,0)("IcapConfig: class_head = %d\n", (int) cfg->class_head); + debug(3,0)("IcapConfig: access_head = %d\n", (int) cfg->access_head); + + debug(3,0) ("IcapConfig: services =\n"); + for (s_iter = cfg->service_head; s_iter; s_iter = s_iter->next) { + printf(" %s: \n", s_iter->name); + printf(" bypass = %d\n", s_iter->bypass); + printf(" hostname = %s\n", s_iter->hostname); + printf(" port = %d\n", s_iter->port); + printf(" resource = %s\n", s_iter->resource); + } + debug(3,0) ("IcapConfig: classes =\n"); + for (c_iter = cfg->class_head; c_iter; c_iter = c_iter->next) { + printf(" %s: \n", c_iter->name); + printf(" services = \n"); + for (isl_iter = c_iter->isl; isl_iter; isl_iter = isl_iter->next) { + printf(" %s\n", isl_iter->service->name); + } + } + debug(3,0)("IcapConfig: access =\n"); + for (a_iter = cfg->access_head; a_iter; a_iter = a_iter->next) { + printf(" service_name = %s\n", a_iter->service_name); + printf(" access = %s", a_iter->access->allow ? "allow" : "deny"); + for (l = a_iter->access->acl_list; l != NULL; l = l->next) { + printf(" %s%s", + l->op ? null_string : "!", + l->acl->name); + } + printf("\n"); + } +} +#endif /* HS_FEAT_ICAP */ static void parse_kb_size_t(size_t * var) Index: squid/src/cbdata.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cbdata.c,v retrieving revision 1.14 retrieving revision 1.14.32.1 diff -u -r1.14 -r1.14.32.1 --- squid/src/cbdata.c 18 Oct 2001 20:52:11 -0000 1.14 +++ squid/src/cbdata.c 4 Apr 2003 16:54:25 -0000 1.14.32.1 @@ -1,6 +1,6 @@ /* - * $Id: cbdata.c,v 1.14 2001/10/18 20:52:11 squidadm Exp $ + * $Id: cbdata.c,v 1.14.32.1 2003/04/04 16:54:25 hno Exp $ * * DEBUG: section 45 Callback Data Registry * ORIGINAL AUTHOR: Duane Wessels @@ -144,6 +144,10 @@ CREATE_CBDATA(statefulhelper); CREATE_CBDATA(helper_stateful_server); CREATE_CBDATA(HttpStateData); +#ifdef HS_FEAT_ICAP + CREATE_CBDATA(IcapStateData); + CREATE_CBDATA(icap_service); +#endif CREATE_CBDATA_FREE(peer, peerDestroy); CREATE_CBDATA(ps_state); CREATE_CBDATA(RemovalPolicy); Index: squid/src/cf.data.pre =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v retrieving revision 1.49.2.33 retrieving revision 1.49.2.33.2.1 diff -u -r1.49.2.33 -r1.49.2.33.2.1 --- squid/src/cf.data.pre 3 Apr 2003 02:20:17 -0000 1.49.2.33 +++ squid/src/cf.data.pre 4 Apr 2003 16:54:30 -0000 1.49.2.33.2.1 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.49.2.33 2003/04/03 02:20:17 squidadm Exp $ +# $Id: cf.data.pre,v 1.49.2.33.2.1 2003/04/04 16:54:30 hno Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -2514,6 +2514,104 @@ DOC_END COMMENT_START + ICAP OPTIONS + ----------------------------------------------------------------------------- +COMMENT_END + +NAME: icap_enable +TYPE: onoff +IFDEF: HS_FEAT_ICAP +COMMENT: on|off +LOC: Config.icapcfg.onoff +DEFAULT: off +DOC_START + If you want to enable the icap client module, set this to on +DOC_END + +NAME: icap_preview_size +TYPE: int +IFDEF: HS_FEAT_ICAP +LOC: Config.icapcfg.preview_size +DEFAULT: -1 +DOC_START + The default size of preview data to be sent to the ICAP server. + -1 means no preview. This value might be overwritten on a per server + basis by OPTIONS requests. +DOC_END + +NAME: icap_send_client_ip +TYPE: onoff +IFDEF: HS_FEAT_ICAP +COMMENT: on|off +LOC: Config.icapcfg.send_client_ip +DEFAULT: off +DOC_START + This adds the header "X-Client-IP" to ICAP requests. +DOC_END + +NAME: icap_service +TYPE: icap_service_type +IFDEF: HS_FEAT_ICAP +LOC: Config.icapcfg +DEFAULT: none +DOC_START + Defines a single icap service + + icap_service servicename vectoring_point bypass service_url + + vectoring_point = reqmod_precache|reqmod_postcache|respmod_precache|respmod_postcache + this specifies, at which point of request processing the icap + service should be plugged in + bypass = 1|0 + if set to 1 and the icap server can not be reached, the request will go + through without being processed by an icap server + service_url = icap://servername:port/service + +Example: +icap_service service_1 reqmod_precache 0 icap://icap1.mydomain.net:1344/reqmod +icap_service service_2 respmod_precache 0 icap://icap2.mydomain.net:1344/respmod +DOC_END + +NAME: icap_class +TYPE: icap_class_type +IFDEF: HS_FEAT_ICAP +LOC: Config.icapcfg +DEFAULT: none +DOC_START + Defines an ICAP service chain. If there are multiple services per + vectoring point, they are processed in the specified order. + + icap_class classname servicename... + +Example: +icap_class class_1 service_1 service_2 +icap class class_2 service_1 service_3 +DOC_END + +NAME: icap_access +TYPE: icap_access_type +IFDEF: HS_FEAT_ICAP +LOC: Config.icapcfg +DEFAULT: none +DOC_START + Redirects a request through an icap service class, depending + on given acls + + icap_access classname allow|deny [!]aclname... + + The icap_access statements are processed in the order they appear in + this configuration file. If an access list matches, the processing stops. + For an "allow" rule, the specified class is used for the request. A "deny" + rule simply stops processing without using the class. You can also use the + special classname "None" there. + + For backward compatibility, it is also possible to use services + directly here. +Example: +icap_access class_1 allow all +DOC_END + +COMMENT_START MISCELLANEOUS ----------------------------------------------------------------------------- COMMENT_END Index: squid/src/cf_gen_defines =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf_gen_defines,v retrieving revision 1.5 retrieving revision 1.5.48.1 diff -u -r1.5 -r1.5.48.1 --- squid/src/cf_gen_defines 3 Dec 2001 08:03:21 -0000 1.5 +++ squid/src/cf_gen_defines 4 Apr 2003 16:54:36 -0000 1.5.48.1 @@ -18,6 +18,7 @@ define["USE_UNLINKD"]="--enable-unlinkd" define["USE_USERAGENT_LOG"]="--enable-useragent-log" define["USE_WCCP"]="--enable-wccp" + define["HS_FEAT_ICAP"]="--enable-icap-support" } /^IFDEF:/ { if (define[$2] != "") Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.47.2.28 retrieving revision 1.47.2.28.2.1 diff -u -r1.47.2.28 -r1.47.2.28.2.1 --- squid/src/client_side.c 20 Feb 2003 03:22:00 -0000 1.47.2.28 +++ squid/src/client_side.c 4 Apr 2003 16:54:36 -0000 1.47.2.28.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.47.2.28 2003/02/20 03:22:00 squidadm Exp $ + * $Id: client_side.c,v 1.47.2.28.2.1 2003/04/04 16:54:36 hno Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -35,6 +35,20 @@ #include "squid.h" +/* I am using some of these functions in ICAP */ +#ifdef HS_FEAT_ICAP +#define STATIC +#else +#define STATIC static +#endif + +/* I am using some of these functions in ICAP */ +#ifdef HS_FEAT_ICAP +#define STATIC +#else +#define STATIC static +#endif + #if IPF_TRANSPARENT #if HAVE_SYS_IOCTL_H #include @@ -89,15 +103,15 @@ static CWCB clientWriteComplete; static CWCB clientWriteBodyComplete; -static PF clientReadRequest; -static PF connStateFree; -static PF requestTimeout; +STATIC PF clientReadRequest; +STATIC PF connStateFree; +STATIC PF requestTimeout; static PF clientLifetimeTimeout; static int clientCheckTransferDone(clientHttpRequest *); static int clientGotNotEnough(clientHttpRequest *); static void checkFailureRatio(err_type, hier_code); static void clientProcessMiss(clientHttpRequest *); -static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep); +STATIC void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep); static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri); static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *); static RH clientRedirectDone; @@ -107,10 +121,10 @@ static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request); static int checkAccelOnly(clientHttpRequest *); #if USE_IDENT -static IDCB clientIdentDone; +STATIC IDCB clientIdentDone; #endif static int clientOnlyIfCached(clientHttpRequest * http); -static STCB clientSendMoreData; +STATIC STCB clientSendMoreData; static STCB clientCacheHit; static void clientSetKeepaliveFlag(clientHttpRequest *); static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); @@ -147,7 +161,7 @@ } #if USE_IDENT -static void +STATIC void clientIdentDone(const char *ident, void *data) { ConnStateData *conn = data; @@ -339,6 +353,13 @@ http->request = requestLink(new_request); } clientInterpretRequestHeaders(http); +#if HS_FEAT_ICAP + /* only for testing, try to do aclCheck for icap */ + http->request->flags.do_icap = 0; + if (Config.icapcfg.onoff) + if (icapCheckAcl(http)) + http->request->flags.do_icap = 1; +#endif #if HEADERS_LOG headersLog(0, 1, request->method, request); #endif @@ -872,7 +893,7 @@ } /* This is a handler normally called by comm_close() */ -static void +STATIC void connStateFree(int fd, void *data) { ConnStateData *connState = data; @@ -1294,7 +1315,7 @@ * adds extra entries if we have more info than origin server * adds Squid specific entries */ -static void +STATIC void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep) { HttpHeader *hdr = &rep->header; @@ -1414,7 +1435,7 @@ httpHdrMangleList(hdr, request); } -static HttpReply * +STATIC HttpReply * clientBuildReply(clientHttpRequest * http, const char *buf, size_t size) { HttpReply *rep = httpReplyCreate(); @@ -1862,7 +1883,7 @@ * accepts chunk of a http message in buf, parses prefix, filters headers and * such, writes processed message to the client's socket */ -static void +STATIC void clientSendMoreData(void *data, char *buf, ssize_t size) { clientHttpRequest *http = data; @@ -2808,7 +2829,7 @@ return http; } -static int +STATIC int clientReadDefer(int fdnotused, void *data) { ConnStateData *conn = data; @@ -2818,7 +2839,7 @@ return conn->defer.until > squid_curtime; } -static void +STATIC void clientReadRequest(int fd, void *data) { ConnStateData *conn = data; @@ -3048,9 +3069,21 @@ if (request->method == METHOD_CONNECT) { /* Stop reading requests... */ commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); +#ifdef HS_FEAT_ICAP + /* I need to read the modified request header from icap server - + allow me. If it has come through Accept go ahead and service.. + else don;t */ + if (conn->me.sin_family) +#endif clientAccessCheck(http); break; } else { +#ifdef HS_FEAT_ICAP + /* I need to read the modified request header from icap server - + allow me. If it has come through Accept go ahead and service.. + else don;t */ + if (conn->me.sin_family) +#endif clientAccessCheck(http); continue; /* while offset > 0 && body.size_left == 0 */ } @@ -3201,7 +3234,7 @@ } /* general lifetime handler for HTTP requests */ -static void +STATIC void requestTimeout(int fd, void *data) { #if THIS_CONFUSES_PERSISTENT_CONNECTION_AWARE_BROWSERS_AND_USERS @@ -3326,8 +3359,9 @@ commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0); commSetDefer(fd, clientReadDefer, connState); clientdbEstablished(peer.sin_addr, 1); - assert(N); - (*N)++; + /* fix this later */ + assert(N); + (*N)++; } } Index: squid/src/comm.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/comm.c,v retrieving revision 1.18.6.2 retrieving revision 1.18.6.2.12.1 diff -u -r1.18.6.2 -r1.18.6.2.12.1 --- squid/src/comm.c 1 Apr 2002 10:26:59 -0000 1.18.6.2 +++ squid/src/comm.c 4 Apr 2003 16:54:56 -0000 1.18.6.2.12.1 @@ -1,6 +1,6 @@ /* - * $Id: comm.c,v 1.18.6.2 2002/04/01 10:26:59 squidadm Exp $ + * $Id: comm.c,v 1.18.6.2.12.1 2003/04/04 16:54:56 hno Exp $ * * DEBUG: section 5 Socket Functions * AUTHOR: Harvest Derived @@ -448,7 +448,8 @@ F->timeout_data = NULL; return F->timeout = 0; } - assert(handler || F->timeout_handler); + /* TODO: fix ICAP code, that this assertion can be taken in again */ + /* assert(handler || F->timeout_handler); */ if (handler || data) { F->timeout_handler = handler; F->timeout_data = data; Index: squid/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/enums.h,v retrieving revision 1.29.2.8 retrieving revision 1.29.2.8.2.1 diff -u -r1.29.2.8 -r1.29.2.8.2.1 --- squid/src/enums.h 21 Jan 2003 03:15:11 -0000 1.29.2.8 +++ squid/src/enums.h 4 Apr 2003 16:55:10 -0000 1.29.2.8.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.29.2.8 2003/01/21 03:15:11 squidadm Exp $ + * $Id: enums.h,v 1.29.2.8.2.1 2003/04/04 16:55:10 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -609,6 +609,12 @@ MEM_TLV, MEM_SWAP_LOG_DATA, MEM_CLIENT_REQ_BUF, +#if HS_FEAT_ICAP + MEM_ICAP_OPT_DATA, + MEM_ICAP_SERVICE_LIST, + MEM_ICAP_CLASS, + MEM_ICAP_ACCESS, +#endif MEM_MAX } mem_type; @@ -706,9 +712,25 @@ CBDATA_RemovalPolicyWalker, CBDATA_RemovalPurgeWalker, CBDATA_store_client, +#ifdef HS_FEAT_ICAP + CBDATA_IcapStateData, + CBDATA_icap_service, +#endif CBDATA_FIRST_CUSTOM_TYPE = 1000 } cbdata_type; + +/* + * ICAP states: Maily required for Preview support for RESPMOD. + */ +typedef enum { + ICAP_EndOfInputData = 1, /* No more data to be expected on HTTP connection */ + ICAP_PreviewDone = 2, /* Handling of preview data finished or no preview at all */ + ICAP_WaitForPreviewReply = 4, /* Expect reply from ICAP server after preview */ + ICAP_WaitForReply = 8, /* Expect final reply from ICAP server */ + ICAP_GotReply = 16, +} icapState; + /* * Return codes from checkVary(request) */ @@ -738,4 +760,67 @@ #endif +#if HS_FEAT_ICAP +typedef enum { + ICAP_STATUS_NONE = 0, + ICAP_STATUS_CONTINUE = 100, + ICAP_STATUS_SWITCHING_PROTOCOLS = 101, + ICAP_STATUS_STATUS_OK = 200, + ICAP_CREATED = 201, + ICAP_STATUS_ACCEPTED = 202, + ICAP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, + ICAP_STATUS_NO_MODIFICATION_NEEDED = 204, + ICAP_STATUS_RESET_CONTENT = 205, + ICAP_STATUS_PARTIAL_CONTENT = 206, + ICAP_STATUS_MULTIPLE_CHOICES = 300, + ICAP_STATUS_MOVED_PERMANENTLY = 301, + ICAP_STATUS_MOVED_TEMPORARILY = 302, + ICAP_STATUS_SEE_OTHER = 303, + ICAP_STATUS_NOT_MODIFIED = 304, + ICAP_STATUS_USE_PROXY = 305, + ICAP_STATUS_BAD_REQUEST = 400, + ICAP_STATUS_UNAUTHORIZED = 401, + ICAP_STATUS_PAYMENT_REQUIRED = 402, + ICAP_STATUS_FORBIDDEN = 403, + ICAP_STATUS_SERVICE_NOT_FOUND = 404, + ICAP_STATUS_METHOD_NOT_ALLOWED = 405, + ICAP_STATUS_NOT_ACCEPTABLE = 406, + ICAP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, + ICAP_STATUS_REQUEST_TIMEOUT = 408, + ICAP_STATUS_CONFLICT = 409, + ICAP_STATUS_GONE = 410, + ICAP_STATUS_LENGTH_REQUIRED = 411, + ICAP_STATUS_PRECONDITION_FAILED = 412, + ICAP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413, + ICAP_STATUS_REQUEST_URI_TOO_LARGE = 414, + ICAP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, + ICAP_STATUS_INTERNAL_SERVER_ERROR = 500, + ICAP_STATUS_NOT_IMPLEMENTED = 501, + ICAP_STATUS_BAD_GATEWAY = 502, + ICAP_STATUS_SERVICE_OVERLOADED = 503, + ICAP_STATUS_GATEWAY_TIMEOUT = 504, + ICAP_STATUS_ICAP_VERSION_NOT_SUPPORTED = 505, + ICAP_STATUS_INVALID_HEADER = 600 +} icap_status; + +/* + * these values are used as index in an array, so it seems to be better to + * assign some numbers + */ +typedef enum { + ICAP_SERVICE_REQMOD_PRECACHE = 0, + ICAP_SERVICE_REQMOD_POSTCACHE = 1, + ICAP_SERVICE_RESPMOD_PRECACHE = 2, + ICAP_SERVICE_RESPMOD_POSTCACHE = 3, + ICAP_SERVICE_MAX = 4 +} icap_service_t; + +typedef enum { + ICAP_METHOD_NONE, + ICAP_METHOD_OPTION, + ICAP_METHOD_REQMOD, + ICAP_METHOD_RESPMOD +} icap_method_t; +#endif /* HS_FEAT_ICAP */ + #endif /* SQUID_ENUMS_H */ Index: squid/src/forward.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/forward.c,v retrieving revision 1.13.6.3 retrieving revision 1.13.6.3.2.1 diff -u -r1.13.6.3 -r1.13.6.3.2.1 --- squid/src/forward.c 18 Mar 2003 03:23:09 -0000 1.13.6.3 +++ squid/src/forward.c 4 Apr 2003 16:55:26 -0000 1.13.6.3.2.1 @@ -1,6 +1,6 @@ /* - * $Id: forward.c,v 1.13.6.3 2003/03/18 03:23:09 squidadm Exp $ + * $Id: forward.c,v 1.13.6.3.2.1 2003/04/04 16:55:26 hno Exp $ * * DEBUG: section 17 Request Forwarding * AUTHOR: Duane Wessels @@ -36,11 +36,18 @@ #include "squid.h" +/* I am using some of these functions in ICAP */ +#ifdef HS_FEAT_ICAP +#define STATIC +#else +#define STATIC static +#endif + static PSC fwdStartComplete; static void fwdDispatch(FwdState *); -static void fwdConnectStart(void *); /* should be same as EVH */ -static void fwdStateFree(FwdState * fwdState); -static PF fwdConnectTimeout; +STATIC void fwdConnectStart(void *); /* should be same as EVH */ +STATIC void fwdStateFree(FwdState * fwdState); +STATIC PF fwdConnectTimeout; static PF fwdServerClosed; static CNCB fwdConnectDone; static int fwdCheckRetry(FwdState * fwdState); @@ -77,7 +84,7 @@ memFree(fs, MEM_FWD_SERVER); } -static void +STATIC void fwdStateFree(FwdState * fwdState) { StoreEntry *e = fwdState->entry; @@ -273,7 +280,7 @@ current = NULL; } -static void +STATIC void fwdConnectTimeout(int fd, void *data) { FwdState *fwdState = data; @@ -351,7 +358,7 @@ return aclMapTOS(Config.accessList.outgoing_tos, &ch); } -static void +STATIC void fwdConnectStart(void *data) { FwdState *fwdState = data; @@ -716,6 +723,13 @@ fwdUnregister(int fd, FwdState * fwdState) { debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry)); +#if defined (HS_FEAT_ICAP) && defined (ICAP_CHUNKED) + /* ugly hack to get not so much assertions + * problem is, that fd might be different from fwd fd, because + * of the icap connection + */ + fd = fwdState->server_fd; +#endif assert(fd == fwdState->server_fd); assert(fd > -1); comm_remove_close_handler(fd, fwdServerClosed, fwdState); Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.17.6.3 retrieving revision 1.17.6.3.6.1 diff -u -r1.17.6.3 -r1.17.6.3.6.1 --- squid/src/http.c 7 Sep 2002 23:16:47 -0000 1.17.6.3 +++ squid/src/http.c 4 Apr 2003 16:55:31 -0000 1.17.6.3.6.1 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.17.6.3 2002/09/07 23:16:47 squidadm Exp $ + * $Id: http.c,v 1.17.6.3.6.1 2003/04/04 16:55:31 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -45,17 +45,25 @@ static CWCB httpSendComplete; static CWCB httpSendRequestEntry; -static PF httpReadReply; -static void httpSendRequest(HttpStateData *); -static PF httpStateFree; -static PF httpTimeout; +/* I am using some of these functions in ICAP */ +#ifdef HS_FEAT_ICAP +#define STATIC +#define ICAP_FIELD(httpState) (httpState)->icap +#else +#define STATIC static +#endif + +STATIC PF httpReadReply; +STATIC void httpSendRequest(HttpStateData *); +STATIC PF httpStateFree; +STATIC PF httpTimeout; static void httpCacheNegatively(StoreEntry *); static void httpMakePrivate(StoreEntry *); static void httpMakePublic(StoreEntry *); static int httpCachableReply(HttpStateData *); static void httpMaybeRemovePublic(StoreEntry *, http_status); -static void +STATIC void httpStateFree(int fd, void *data) { HttpStateData *httpState = data; @@ -64,6 +72,13 @@ #endif if (httpState == NULL) return; + debug(11, 3) ("httpStateFree: FD %d, httpState = %p\n", fd, data); +#ifdef HS_FEAT_ICAP + if (httpState->icap) { + icapStateFree (httpState->icap); + httpState->icap = NULL; + } +#endif storeUnlockObject(httpState->entry); if (httpState->reply_hdr) { memFree(httpState->reply_hdr, MEM_8K_BUF); @@ -86,7 +101,7 @@ return 1; } -static void +STATIC void httpTimeout(int fd, void *data) { HttpStateData *httpState = data; @@ -482,19 +497,18 @@ } static int -httpPconnTransferDone(HttpStateData * httpState) +httpPconnTransferDone(int fd, HttpStateData * httpState) { /* return 1 if we got the last of the data on a persistent connection */ MemObject *mem = httpState->entry->mem_obj; HttpReply *reply = mem->reply; int clen; - debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd); + + debug(11, 3) ("httpPconnTransferDone: FD %d\n", fd); /* * If we didn't send a keep-alive request header, then this * can not be a persistent connection. */ - if (!httpState->flags.keepalive) - return 0; /* * What does the reply have to say about keep-alive? */ @@ -507,34 +521,52 @@ * and an error status code, and we might have to wait until * the server times out the socket. */ + if (!reply->keep_alive) return 0; +#if defined (HS_FEAT_ICAP) && defined (ICAP_CHUNKED) + if (httpState->icap && httpState->icap->icap_fd == fd && httpState->icap->chunk_size == -2) { + /* zero end chunk reached */ + debug(11, 5) ("httpPconnTransferDone: zero end chunk on ICAP connection reached\n"); + return 1; + } +#endif debug(11, 5) ("httpPconnTransferDone: content_length=%d\n", reply->content_length); /* If we haven't seen the end of reply headers, we are not done */ if (httpState->reply_hdr_state < 2) return 0; + clen = httpReplyBodySize(httpState->request->method, reply); /* If there is no message body, we can be persistent */ - if (0 == clen) + if (0 == clen) { + debug(11, 3) ("GEE:httpPconnTransferDone: FD %d no content returning 1\n", httpState->fd); return 1; + } /* If the body size is unknown we must wait for EOF */ if (clen < 0) return 0; + + /* If the body size is known, we must wait until we've gotten all of it. */ if (mem->inmem_hi < reply->content_length + reply->hdr_sz) return 0; /* We got it all */ + debug(11, 3) ("GEE:httpPconnTransferDone: FD %d we got it all %d %d %d\n", + httpState->fd, (int) mem->inmem_hi, reply->content_length, reply->hdr_sz); return 1; } /* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ /* XXX this function is too long! */ -static void +STATIC void httpReadReply(int fd, void *data) { HttpStateData *httpState = data; +#ifdef HS_FEAT_ICAP + IcapStateData *icap; +#endif LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF); StoreEntry *entry = httpState->entry; const request_t *request = httpState->request; @@ -551,6 +583,7 @@ else delay_id = delayMostBytesAllowed(entry->mem_obj); #endif + debug(11, 5) ("httpReadReply: FD %d: httpState %p.\n", fd, data); if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; @@ -621,6 +654,12 @@ * we want to process the reply headers. */ httpProcessReplyHeader(httpState, buf, len); +#ifdef HS_FEAT_ICAP + if (ICAP_FIELD(httpState) && ICAP_FIELD(httpState)->http_fd == fd) { + icapSendRespMod(httpState, buf, len, 1); + return; + } +#endif fwdComplete(httpState->fwd); comm_close(fd); } else { @@ -639,7 +678,32 @@ EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); } } - storeAppend(entry, buf, len); +#if defined (HS_FEAT_ICAP) && defined (ICAP_CHUNKED) + /* read data on ICAP connection in chunked encoding */ + if (httpState->icap && httpState->icap->icap_fd == fd) { + if (icapReadChunkedBody (fd, httpState, len, buf)) + return; + } else +#endif + if (fd == httpState->fd) + storeAppend(entry, buf, len); + + + debug(11, 5) ("httpReadReply: after storeAppend FD %d read %d\n", fd, len); + +#ifdef ICAP_CHUNKED + /* + * when headers are complete and no body is specified in encapsulated header + * we probably can finish this request + */ + icap = ICAP_FIELD(httpState); + if (icap && icap->reqmod && icap->enc_null_body >= 0 && httpState->reply_hdr_state == 2) { + fwdComplete(httpState->fwd); + comm_close(fd); + return; + } +#endif + if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* * the above storeAppend() call could ABORT this entry, @@ -647,8 +711,15 @@ * there's nothing for us to do. */ (void) 0; - } else if (httpPconnTransferDone(httpState)) { + } else if (httpPconnTransferDone(fd, httpState)) { /* yes we have to clear all these! */ +#ifdef HS_FEAT_ICAP + /* only enter respmod if we are not in reqmod mode */ + if (ICAP_FIELD(httpState) && !ICAP_FIELD(httpState)->reqmod && ICAP_FIELD(httpState)->http_fd == fd) { + icapSendRespMod(httpState, buf, len, 1); + return; + } +#endif commSetDefer(fd, NULL, NULL); commSetTimeout(fd, -1, NULL, NULL); commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0); @@ -662,6 +733,12 @@ httpState->fd = -1; httpStateFree(fd, httpState); } else { +#ifdef HS_FEAT_ICAP + /* don't enter respmod for reqmod replies from icap server */ + if (ICAP_FIELD(httpState) && !ICAP_FIELD(httpState)->reqmod && ICAP_FIELD(httpState)->http_fd == fd) { + icapSendRespMod(httpState, buf, len, 0); + } else +#endif /* Wait for EOF condition */ commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); } @@ -697,6 +774,12 @@ return; } else { /* Schedule read reply. */ +#if defined (HS_FEAT_ICAP) + if (httpState->orig_request->flags.do_icap) { + if (startICAPrespmod(httpState) >= 0) + return; + } +#endif commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0); /* * Set the read timeout here because it hasn't been set yet. @@ -707,7 +790,13 @@ * request bodies. */ commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState); +#ifdef HS_FEAT_ICAP + /* Read fully - don't put limits on the read ahead count */ + /* Oh! I broke my head for this */ + commSetDefer(fd, NULL, NULL); +#else commSetDefer(fd, fwdCheckDeferRead, entry); +#endif } } @@ -896,8 +985,11 @@ if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) { const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request); httpHdrCcSetMaxAge(cc, getMaxAge(url)); +#ifndef HS_FEAT_ICAP + /* Don;t bother - if the url you want to cache is redirected? */ if (strLen(request->urlpath)) assert(strstr(url, strBuf(request->urlpath))); +#endif } if (flags.only_if_cached) EBIT_SET(cc->mask, CC_ONLY_IF_CACHED); @@ -946,7 +1038,7 @@ return mb->size - offset; } /* This will be called when connect completes. Write request. */ -static void +STATIC void httpSendRequest(HttpStateData * httpState) { MemBuf mb; @@ -1043,12 +1135,19 @@ httpState->request = requestLink(orig_req); httpState->orig_request = requestLink(orig_req); } +#ifdef HS_FEAT_ICAP + if (httpState->orig_request->flags.do_icap) { + if (startICAPreqmod(httpState) >= 0) + return; + } +#endif /* * register the handler to free HTTP state data when the FD closes */ comm_add_close_handler(fd, httpStateFree, httpState); statCounter.server.all.requests++; statCounter.server.http.requests++; + httpSendRequest(httpState); /* * We used to set the read timeout here, but not any more. @@ -1131,3 +1230,4 @@ version->major = major; version->minor = minor; } + Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.28.6.8 retrieving revision 1.28.6.8.2.1 diff -u -r1.28.6.8 -r1.28.6.8.2.1 --- squid/src/main.c 30 Jan 2003 03:18:32 -0000 1.28.6.8 +++ squid/src/main.c 4 Apr 2003 16:55:37 -0000 1.28.6.8.2.1 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.28.6.8 2003/01/30 03:18:32 squidadm Exp $ + * $Id: main.c,v 1.28.6.8.2.1 2003/04/04 16:55:37 hno Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -158,6 +158,11 @@ case 'h': usage(); break; +#if 0 + case 'i': + enable_icap(optarg); + break; +#endif case 'k': if ((int) strlen(optarg) < 1) usage(); @@ -368,6 +373,9 @@ idnsInit(); #endif redirectInit(); +#ifdef HS_FEAT_ICAP + icapInit(); +#endif authenticateInit(&Config.authConfig); externalAclInit(); #if USE_WCCP @@ -411,6 +419,9 @@ dnsInit(); #endif redirectInit(); +#ifdef HS_FEAT_ICAP + icapInit(); +#endif authenticateInit(&Config.authConfig); externalAclInit(); } @@ -496,6 +507,9 @@ idnsInit(); #endif redirectInit(); +#ifdef HS_FEAT_ICAP + icapInit(); +#endif authenticateInit(&Config.authConfig); externalAclInit(); useragentOpenLog(); Index: squid/src/mem.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/mem.c,v retrieving revision 1.13 retrieving revision 1.13.28.1 diff -u -r1.13 -r1.13.28.1 --- squid/src/mem.c 7 Sep 2001 23:55:49 -0000 1.13 +++ squid/src/mem.c 4 Apr 2003 16:55:41 -0000 1.13.28.1 @@ -1,6 +1,6 @@ /* - * $Id: mem.c,v 1.13 2001/09/07 23:55:49 squidadm Exp $ + * $Id: mem.c,v 1.13.28.1 2003/04/04 16:55:41 hno Exp $ * * DEBUG: section 13 High Level Memory Pool Management * AUTHOR: Harvest Derived @@ -243,6 +243,13 @@ memDataInit(MEM_CLIENT_REQ_BUF, "clientRequestBuffer", CLIENT_REQ_BUF_SZ, 0); memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0); +#ifdef HS_FEAT_ICAP + memDataInit(MEM_ICAP_OPT_DATA, "IcapOptData", sizeof(IcapOptData), 0); + memDataInit(MEM_ICAP_SERVICE_LIST, "icap_service_list", sizeof(icap_service_list),0); + memDataInit(MEM_ICAP_CLASS, "icap_class", sizeof(icap_class), 0); + memDataInit(MEM_ICAP_ACCESS, "icap_access", sizeof(icap_access), 0); +#endif + /* init string pools */ for (i = 0; i < mem_str_pool_count; i++) { StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size); Index: squid/src/mk-string-arrays.pl =================================================================== RCS file: /cvsroot/squid-sf//squid/src/mk-string-arrays.pl,v retrieving revision 1.2 retrieving revision 1.2.140.1 diff -u -r1.2 -r1.2.140.1 --- squid/src/mk-string-arrays.pl 23 Oct 2000 15:04:21 -0000 1.2 +++ squid/src/mk-string-arrays.pl 4 Apr 2003 16:55:44 -0000 1.2.140.1 @@ -1,5 +1,5 @@ #****************************************************************************** -# $Id: mk-string-arrays.pl,v 1.2 2000/10/23 15:04:21 hno Exp $ +# $Id: mk-string-arrays.pl,v 1.2.140.1 2003/04/04 16:55:44 hno Exp $ # # File: mk-strs.pl # @@ -16,6 +16,7 @@ $pat{'icp_opcode'} = "icp_opcode_str"; $pat{'swap_log_op'} = "swap_log_op_str"; $pat{'lookup_t'} = "lookup_t_str"; +$pat{'icap_service_t'} = "icap_service_type_str"; $state = 0; # start state while (<>) { Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.41.6.13 retrieving revision 1.41.6.13.2.1 diff -u -r1.41.6.13 -r1.41.6.13.2.1 --- squid/src/protos.h 3 Jan 2003 03:16:50 -0000 1.41.6.13 +++ squid/src/protos.h 4 Apr 2003 16:55:45 -0000 1.41.6.13.2.1 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.41.6.13 2003/01/03 03:16:50 squidadm Exp $ + * $Id: protos.h,v 1.41.6.13.2.1 2003/04/04 16:55:45 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1347,4 +1347,23 @@ extern void externalAclShutdown(void); extern char *strtokFile(void); +#ifdef HS_FEAT_ICAP +/* icap.c */ +int icapInit(); +const char* icapServiceToStr(const icap_service_t type); +icap_service_t icapServiceToType(const char *s); +void icapServiceListFree(icap_service_list* isl[]); +void icapServiceListDump(icap_service_list* isl[]); +int icapCheckAcl( clientHttpRequest *http ); +void icapStateFree (IcapStateData *icap); +int icapReadChunkSize(void *data, char *buf, int len); +int icapReadChunkedBody (int fd, void* data, int len, char* buf); +int icapSendRespMod(HttpStateData * httpState, void *buf, int len, int theEnd); +int startICAPrespmod(HttpStateData * httpState); +int startICAPreqmod(HttpStateData * httpState); +/* icap_opt.c */ +void icapOptInit(); +void icapOptShutdown(); +#endif + #endif /* SQUID_PROTOS_H */ Index: squid/src/squid.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/squid.h,v retrieving revision 1.13.6.6 retrieving revision 1.13.6.6.2.1 diff -u -r1.13.6.6 -r1.13.6.6.2.1 --- squid/src/squid.h 10 Mar 2003 03:23:44 -0000 1.13.6.6 +++ squid/src/squid.h 4 Apr 2003 16:55:49 -0000 1.13.6.6.2.1 @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.13.6.6 2003/03/10 03:23:44 squidadm Exp $ + * $Id: squid.h,v 1.13.6.6.2.1 2003/04/04 16:55:49 hno Exp $ * * AUTHOR: Duane Wessels * @@ -38,6 +38,14 @@ #include "config.h" /* + * experimental defines for ICAP; apparently this Squid-Icap *requires* + * ICAP_CHUNKED : Basile Starynkevitch, june 14th 2002 + */ + +#ifdef HS_FEAT_ICAP +#define ICAP_CHUNKED 1 +#endif +/* * On some systems, FD_SETSIZE is set to something lower than the * actual number of files which can be opened. IRIX is one case, * NetBSD is another. So here we increase FD_SETSIZE to our Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.48.2.9 retrieving revision 1.48.2.9.2.1 diff -u -r1.48.2.9 -r1.48.2.9.2.1 --- squid/src/structs.h 21 Jan 2003 03:15:11 -0000 1.48.2.9 +++ squid/src/structs.h 4 Apr 2003 16:55:53 -0000 1.48.2.9.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.48.2.9 2003/01/21 03:15:11 squidadm Exp $ + * $Id: structs.h,v 1.48.2.9.2.1 2003/04/04 16:55:53 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -373,6 +373,18 @@ wordlist *args; }; +#if HS_FEAT_ICAP +struct _IcapConfig { + int onoff; + icap_service *service_head; + /* icap_service_list *service_list_head; */ + icap_class *class_head; + icap_access *access_head; + int preview_size; + int send_client_ip; +}; +#endif /* HS_FEAT_ICAP */ + struct _SquidConfig { struct { size_t maxSize; @@ -691,6 +703,9 @@ char *store_dir_select_algorithm; int sleep_after_fork; /* microseconds */ external_acl *externalAclHelperList; +#ifdef HS_FEAT_ICAP + IcapConfig icapcfg; +#endif }; struct _SquidConfig2 { @@ -968,6 +983,76 @@ unsigned int only_if_cached:1; }; +#ifdef HS_FEAT_ICAP +struct _IcapStateData { + int icap_fd; + int http_fd; + int sc; + icapState state; + icap_service *current_service; + int enc_res_hdr; + int enc_null_body; + int enc_res_body; + ushort reqmod; + MemBuf buffer; + int chunk_size; + int preview_size; +}; + +struct _icap_service { + icap_service *next; + char *name; /* name to be used when referencing ths service */ + char *uri; /* uri of server/service to use */ + char *type_name; /* {req|resp}mod_{pre|post}cache */ + + char *hostname; + unsigned short int port; + char *resource; + icap_service_t type; /* parsed type */ + icap_method_t method; + ushort bypass; /* flag: bypass allowed */ + ushort unreachable; /* flag: set to 1 if options request fails */ + IcapOptData *opt; /* temp data needed during opt request */ + struct { + unsigned int allow_204:1; + } flags; + int preview; + String istag; + String transfer_preview; + String transfer_ignore; + String transfer_complete; + int max_connections; + int options_ttl; +}; + +struct _icap_service_list { + icap_service_list* next; + icap_service* service; +}; + +struct _icap_class { + icap_class *next; + char* name; + wordlist* services; + icap_service_list *isl; + ushort hidden; /* for unnamed classes */ +}; + +struct _icap_access { + icap_access *next; + char *service_name; + icap_class *class; + acl_access *access; +}; + +struct _IcapOptData { + char *buf; + off_t offset; + size_t size; +}; + +#endif + struct _HttpStateData { StoreEntry *entry; request_t *request; @@ -980,8 +1065,12 @@ int fd; http_state_flags flags; FwdState *fwd; +#ifdef HS_FEAT_ICAP + struct _IcapStateData *icap; +#endif }; + struct _icpUdpData { struct sockaddr_in address; void *msg; @@ -1605,6 +1694,11 @@ unsigned int internal:1; unsigned int body_sent:1; unsigned int reset_tcp:1; +#if HS_FEAT_ICAP + /* if any icap acl matches, this is set to true */ + unsigned int do_icap:1; +#endif + }; struct _link_list { @@ -1661,6 +1755,11 @@ char *peer_login; /* Configured peer login:password */ time_t lastmod; /* Used on refreshes */ const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */ +#if HS_FEAT_ICAP + /* linked lists of pointers to icap_services to use */ + /* icap_service_list* isl[ICAP_SERVICE_MAX]; */ + icap_class *class; +#endif }; struct _cachemgr_passwd { Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.25.6.1 retrieving revision 1.25.6.1.6.1 diff -u -r1.25.6.1 -r1.25.6.1.6.1 --- squid/src/typedefs.h 23 Jun 2002 13:56:26 -0000 1.25.6.1 +++ squid/src/typedefs.h 4 Apr 2003 16:55:59 -0000 1.25.6.1.6.1 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.25.6.1 2002/06/23 13:56:26 squidadm Exp $ + * $Id: typedefs.h,v 1.25.6.1.6.1 2003/04/04 16:55:59 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -111,6 +111,15 @@ typedef struct _HttpBody HttpBody; typedef struct _HttpReply HttpReply; typedef struct _HttpStateData HttpStateData; +#ifdef HS_FEAT_ICAP +typedef struct _IcapStateData IcapStateData; +typedef struct _IcapConfig IcapConfig; +typedef struct _icap_service icap_service; +typedef struct _icap_service_list icap_service_list; +typedef struct _icap_class icap_class; +typedef struct _icap_access icap_access; +typedef struct _IcapOptData IcapOptData; +#endif typedef struct _icpUdpData icpUdpData; typedef struct _clientHttpRequest clientHttpRequest; typedef struct _ConnStateData ConnStateData;