=== modified file 'src/ClientRequestContext.h' --- src/ClientRequestContext.h 2012-11-30 11:08:47 +0000 +++ src/ClientRequestContext.h 2012-12-02 11:17:15 +0000 @@ -17,72 +17,77 @@ class HelperReply; class ClientRequestContext : public RefCountable { public: void *operator new(size_t); void operator delete(void *); ClientRequestContext(ClientHttpRequest *); ~ClientRequestContext(); bool httpStateIsValid(); void hostHeaderVerify(); void hostHeaderIpVerify(const ipcache_addrs* ia, const DnsLookupDetails &dns); void hostHeaderVerifyFailed(const char *A, const char *B); void clientAccessCheck(); void clientAccessCheck2(); void clientAccessCheckDone(const allow_t &answer); void clientRedirectStart(); + void clientStoreIdStart(); void clientRedirectDone(const HelperReply &reply); + void clientStoreIdDone(const HelperReply &reply); void checkNoCache(); void checkNoCacheDone(const allow_t &answer); #if USE_ADAPTATION void adaptationAccessCheck(); #endif #if USE_SSL /** * Initiates and start the acl checklist to check if the a CONNECT * request must be bumped. \retval true if the acl check scheduled, false if no ssl-bump required */ bool sslBumpAccessCheck(); /// The callback function for ssl-bump access check list void sslBumpAccessCheckDone(const allow_t &answer); #endif ClientHttpRequest *http; ACLChecklist *acl_checklist; /* need ptr back so we can unreg if needed */ int redirect_state; + int store_id_state; /** * URL-rewrite/redirect helper may return BH for internal errors. * We attempt to recover by trying the lookup again, but limit the * number of retries to prevent lag and lockups. * This tracks the number of previous failures for the current context. */ uint8_t redirect_fail_count; + uint8_t store_id_fail_count; bool host_header_verify_done; bool http_access_done; bool adapted_http_access_done; #if USE_ADAPTATION bool adaptation_acl_check_done; #endif bool redirect_done; + bool store_id_done; bool no_cache_done; bool interpreted_req_hdrs; bool tosToClientDone; bool nfmarkToClientDone; #if USE_SSL bool sslBumpCheckDone; #endif ErrorState *error; ///< saved error page for centralized/delayed processing bool readNextRequest; ///< whether Squid should read after error handling private: CBDATA_CLASS(ClientRequestContext); }; #endif /* SQUID_CLIENTREQUESTCONTEXT_H */ === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2012-11-30 22:54:46 +0000 +++ src/HttpRequest.cc 2012-12-02 11:20:57 +0000 @@ -130,40 +130,42 @@ #if USE_ADAPTATION adaptHistory_ = NULL; #endif #if ICAP_CLIENT icapHistory_ = NULL; #endif rangeOffsetLimit = -2; //a value of -2 means not checked yet } void HttpRequest::clean() { // we used to assert that the pipe is NULL, but now the request only // points to a pipe that is owned and initiated by another object. body_pipe = NULL; #if USE_AUTH auth_user_request = NULL; #endif safe_free(canonical); + safe_free(store_id); + safe_free(vary_headers); urlpath.clean(); header.clean(); if (cache_control) { delete cache_control; cache_control = NULL; } if (range) { delete range; range = NULL; } myportname.clean(); if (helperNotes) { delete helperNotes; @@ -669,20 +671,28 @@ bool HttpRequest::canHandle1xx() const { // old clients do not support 1xx unless they sent Expect: 100-continue // (we reject all other HDR_EXPECT values so just check for HDR_EXPECT) if (http_ver <= HttpVersion(1,0) && !header.has(HDR_EXPECT)) return false; // others must support 1xx control messages return true; } ConnStateData * HttpRequest::pinnedConnection() { if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned) return clientConnectionManager.get(); return NULL; } + +const char *HttpRequest::urlStoreId() +{ + if (store_id) + return store_id; + else + return urlCanonical((HttpRequest*)this); +} === modified file 'src/HttpRequest.h' --- src/HttpRequest.h 2012-11-30 22:57:54 +0000 +++ src/HttpRequest.h 2012-12-02 11:20:57 +0000 @@ -148,40 +148,42 @@ int host_is_numeric; #if USE_ADAPTATION mutable Adaptation::History::Pointer adaptHistory_; ///< per-HTTP transaction info #endif #if ICAP_CLIENT mutable Adaptation::Icap::History::Pointer icapHistory_; ///< per-HTTP transaction info #endif public: Ip::Address host_addr; #if USE_AUTH Auth::UserRequest::Pointer auth_user_request; #endif unsigned short port; String urlpath; char *canonical; + char *store_id; + RequestFlags flags; HttpHdrRange *range; time_t ims; int imslen; Ip::Address client_addr; #if FOLLOW_X_FORWARDED_FOR Ip::Address indirect_client_addr; #endif /* FOLLOW_X_FORWARDED_FOR */ Ip::Address my_addr; HierarchyLogEntry hier; int dnsWait; ///< sum of DNS lookup delays in milliseconds, for %dt @@ -224,40 +226,42 @@ int parseHeader(const char *parse_start, int len); virtual bool expectingBody(const HttpRequestMethod& unused, int64_t&) const; bool bodyNibbled() const; // the request has a [partially] consumed body int prefixLen(); void swapOut(StoreEntry * e); void pack(Packer * p); static void httpRequestPack(void *obj, Packer *p); static HttpRequest * CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method); static HttpRequest * CreateFromUrl(char * url); ConnStateData *pinnedConnection(); + const char *urlStoreId(); + /** * The client connection manager, if known; * Used for any response actions needed directly to the client. * ie 1xx forwarding or connection pinning state changes */ CbcPointer clientConnectionManager; int64_t getRangeOffsetLimit(); /* the result of this function gets cached in rangeOffsetLimit */ private: const char *packableURI(bool full_uri) const; mutable int64_t rangeOffsetLimit; /* caches the result of getRangeOffsetLimit */ protected: virtual void packFirstLineInto(Packer * p, bool full_uri) const; virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, http_status *error); virtual void hdrCacheInit(); === modified file 'src/SquidConfig.h' --- src/SquidConfig.h 2012-10-29 04:59:58 +0000 +++ src/SquidConfig.h 2012-12-02 11:01:58 +0000 @@ -32,536 +32,536 @@ #include "acl/AclAddress.h" #include "base/RefCount.h" #include "ClientDelayConfig.h" #include "DelayConfig.h" #include "HelperChildConfig.h" #include "HttpHeaderTools.h" #include "icmp/IcmpConfig.h" #include "ip/Address.h" #include "Notes.h" #include "YesNoNone.h" #if USE_SSL #include class sslproxy_cert_sign; class sslproxy_cert_adapt; #endif class acl_access; class AclSizeLimit; class AclDenyInfoList; -namespace Mgr -{ +namespace Mgr { class ActionPasswordList; } // namespace Mgr class CustomLog; class CpuAffinityMap; class external_acl; class HeaderManglers; class RefreshPattern; class RemovalPolicySettings; class SwapDir; -namespace AnyP -{ +namespace AnyP { class PortCfg; } /// the representation of the configuration. POD. -class SquidConfig -{ +class SquidConfig { public: - struct { - /* These should be for the Store::Root instance. - * this needs pluggable parsing to be done smoothly. - */ - int highWaterMark; - int lowWaterMark; - } Swap; - - YesNoNone memShared; ///< whether the memory cache is shared among workers - size_t memMaxSize; - - struct { - int64_t min; - int pct; - int64_t max; - } quickAbort; - int64_t readAheadGap; - RemovalPolicySettings *replPolicy; - RemovalPolicySettings *memPolicy; + struct { + /* These should be for the Store::Root instance. + * this needs pluggable parsing to be done smoothly. + */ + int highWaterMark; + int lowWaterMark; + } Swap; + + YesNoNone memShared; ///< whether the memory cache is shared among workers + size_t memMaxSize; + + struct { + int64_t min; + int pct; + int64_t max; + } quickAbort; + int64_t readAheadGap; + RemovalPolicySettings *replPolicy; + RemovalPolicySettings *memPolicy; #if USE_HTTP_VIOLATIONS - time_t negativeTtl; + time_t negativeTtl; #endif - time_t maxStale; - time_t negativeDnsTtl; - time_t positiveDnsTtl; - time_t shutdownLifetime; - time_t backgroundPingRate; - - struct { - time_t read; - time_t write; - time_t lifetime; - time_t connect; - time_t forward; - time_t peer_connect; - time_t request; - time_t clientIdlePconn; - time_t serverIdlePconn; - time_t siteSelect; - time_t deadPeer; - int icp_query; /* msec */ - int icp_query_max; /* msec */ - int icp_query_min; /* msec */ - int mcast_icp_query; /* msec */ + time_t maxStale; + time_t negativeDnsTtl; + time_t positiveDnsTtl; + time_t shutdownLifetime; + time_t backgroundPingRate; + + struct { + time_t read; + time_t write; + time_t lifetime; + time_t connect; + time_t forward; + time_t peer_connect; + time_t request; + time_t clientIdlePconn; + time_t serverIdlePconn; + time_t siteSelect; + time_t deadPeer; + int icp_query; /* msec */ + int icp_query_max; /* msec */ + int icp_query_min; /* msec */ + int mcast_icp_query; /* msec */ #if !USE_DNSHELPER - time_msec_t idns_retransmit; - time_msec_t idns_query; + time_msec_t idns_retransmit; + time_msec_t idns_query; #endif - } Timeout; - size_t maxRequestHeaderSize; - int64_t maxRequestBodySize; - int64_t maxChunkedRequestBodySize; - size_t maxRequestBufferSize; - size_t maxReplyHeaderSize; - AclSizeLimit *ReplyBodySize; + } Timeout; + size_t maxRequestHeaderSize; + int64_t maxRequestBodySize; + int64_t maxChunkedRequestBodySize; + size_t maxRequestBufferSize; + size_t maxReplyHeaderSize; + AclSizeLimit *ReplyBodySize; - struct { - unsigned short icp; + struct { + unsigned short icp; #if USE_HTCP - unsigned short htcp; + unsigned short htcp; #endif #if SQUID_SNMP - unsigned short snmp; + unsigned short snmp; #endif - } Port; + } Port; - struct { - AnyP::PortCfg *http; + struct { + AnyP::PortCfg *http; #if USE_SSL - AnyP::PortCfg *https; + AnyP::PortCfg *https; #endif - } Sockaddr; + } Sockaddr; #if SQUID_SNMP - struct { - char *configFile; - char *agentInfo; - } Snmp; + struct { + char *configFile; + char *agentInfo; + }Snmp; #endif #if USE_WCCP - struct { - Ip::Address router; - Ip::Address address; - int version; - } Wccp; + struct { + Ip::Address router; + Ip::Address address; + int version; + }Wccp; #endif #if USE_WCCPv2 - struct { - Ip::Address_list *router; - Ip::Address address; - int forwarding_method; - int return_method; - int assignment_method; - int weight; - int rebuildwait; - void *info; - } Wccp2; + struct { + Ip::Address_list *router; + Ip::Address address; + int forwarding_method; + int return_method; + int assignment_method; + int weight; + int rebuildwait; + void *info; + }Wccp2; #endif #if USE_ICMP - IcmpConfig pinger; + IcmpConfig pinger; #endif - char *as_whois_server; + char *as_whois_server; - struct { - char *store; - char *swap; - CustomLog *accesslogs; + struct { + char *store; + char *swap; + CustomLog *accesslogs; #if ICAP_CLIENT - CustomLog *icaplogs; + CustomLog *icaplogs; #endif - int rotateNumber; - } Log; - char *adminEmail; - char *EmailFrom; - char *EmailProgram; - char *effectiveUser; - char *visible_appname_string; - char *effectiveGroup; + int rotateNumber; + } Log; + char *adminEmail; + char *EmailFrom; + char *EmailProgram; + char *effectiveUser; + char *visible_appname_string; + char *effectiveGroup; - struct { + struct { #if USE_DNSHELPER - char *dnsserver; + char *dnsserver; #endif - wordlist *redirect; + wordlist *redirect; + wordlist *store_id; #if USE_UNLINKD - char *unlinkd; + char *unlinkd; #endif - char *diskd; + char *diskd; #if USE_SSL - char *ssl_password; + char *ssl_password; #endif - } Program; + } Program; #if USE_DNSHELPER - HelperChildConfig dnsChildren; + HelperChildConfig dnsChildren; #endif - HelperChildConfig redirectChildren; - time_t authenticateGCInterval; - time_t authenticateTTL; - time_t authenticateIpTTL; - - struct { - char *surrogate_id; - } Accel; - char *appendDomain; - size_t appendDomainLen; - char *pidFilename; - char *netdbFilename; - char *mimeTablePathname; - char *etcHostsPath; - char *visibleHostname; - char *uniqueHostname; - wordlist *hostnameAliases; - char *errHtmlText; - - struct { - char *host; - char *file; - time_t period; - unsigned short port; - } Announce; + HelperChildConfig redirectChildren; + HelperChildConfig storeIdChildren; + time_t authenticateGCInterval; + time_t authenticateTTL; + time_t authenticateIpTTL; + + struct { + char *surrogate_id; + } Accel; + char *appendDomain; + size_t appendDomainLen; + char *pidFilename; + char *netdbFilename; + char *mimeTablePathname; + char *etcHostsPath; + char *visibleHostname; + char *uniqueHostname; + wordlist *hostnameAliases; + char *errHtmlText; + + struct { + char *host; + char *file; + time_t period; + unsigned short port; + } Announce; - struct { + struct { - Ip::Address udp_incoming; - Ip::Address udp_outgoing; + Ip::Address udp_incoming; + Ip::Address udp_outgoing; #if SQUID_SNMP - Ip::Address snmp_incoming; - Ip::Address snmp_outgoing; + Ip::Address snmp_incoming; + Ip::Address snmp_outgoing; #endif - /* FIXME INET6 : this should really be a CIDR value */ - Ip::Address client_netmask; - } Addrs; - size_t tcpRcvBufsz; - size_t udpMaxHitObjsz; - wordlist *hierarchy_stoplist; - wordlist *mcast_group_list; - wordlist *dns_nameservers; - CachePeer *peers; - int npeers; - - struct { - int size; - int low; - int high; - } ipcache; - - struct { - int size; - } fqdncache; - int minDirectHops; - int minDirectRtt; - Mgr::ActionPasswordList *passwd_list; - - struct { - int objectsPerBucket; - int64_t avgObjectSize; - int64_t maxObjectSize; - int64_t minObjectSize; - size_t maxInMemObjSize; - } Store; - - struct { - int high; - int low; - time_t period; - } Netdb; - - struct { - int log_udp; - int res_defnames; - int anonymizer; - int client_db; - int query_icmp; - int icp_hit_stale; - int buffered_logs; - int common_log; - int log_mime_hdrs; - int log_fqdn; - int announce; - int mem_pools; - int test_reachability; - int half_closed_clients; - int refresh_all_ims; + /* FIXME INET6 : this should really be a CIDR value */ + Ip::Address client_netmask; + } Addrs; + size_t tcpRcvBufsz; + size_t udpMaxHitObjsz; + wordlist *hierarchy_stoplist; + wordlist *mcast_group_list; + wordlist *dns_nameservers; + CachePeer *peers; + int npeers; + + struct { + int size; + int low; + int high; + } ipcache; + + struct { + int size; + } fqdncache; + int minDirectHops; + int minDirectRtt; + Mgr::ActionPasswordList *passwd_list; + + struct { + int objectsPerBucket; + int64_t avgObjectSize; + int64_t maxObjectSize; + int64_t minObjectSize; + size_t maxInMemObjSize; + } Store; + + struct { + int high; + int low; + time_t period; + } Netdb; + + struct { + int log_udp; + int res_defnames; + int anonymizer; + int client_db; + int query_icmp; + int icp_hit_stale; + int buffered_logs; + int common_log; + int log_mime_hdrs; + int log_fqdn; + int announce; + int mem_pools; + int test_reachability; + int half_closed_clients; + int refresh_all_ims; #if USE_HTTP_VIOLATIONS - int reload_into_ims; + int reload_into_ims; #endif - int offline; - int redir_rewrites_host; - int prefer_direct; - int nonhierarchical_direct; - int strip_query_terms; - int redirector_bypass; - int ignore_unknown_nameservers; - int client_pconns; - int server_pconns; - int error_pconns; + int offline; + int redir_rewrites_host; + int prefer_direct; + int nonhierarchical_direct; + int strip_query_terms; + int redirector_bypass; + int store_id_bypass; + int ignore_unknown_nameservers; + int client_pconns; + int server_pconns; + int error_pconns; #if USE_CACHE_DIGESTS - int digest_generation; + int digest_generation; #endif - int ie_refresh; - int vary_ignore_expire; - int pipeline_prefetch; - int surrogate_is_remote; - int request_entities; - int detect_broken_server_pconns; - int balance_on_multiple_ip; - int relaxed_header_parser; - int check_hostnames; - int allow_underscore; - int via; - int emailErrData; - int httpd_suppress_version_string; - int global_internal_static; + int ie_refresh; + int vary_ignore_expire; + int pipeline_prefetch; + int surrogate_is_remote; + int request_entities; + int detect_broken_server_pconns; + int balance_on_multiple_ip; + int relaxed_header_parser; + int check_hostnames; + int allow_underscore; + int via; + int emailErrData; + int httpd_suppress_version_string; + int global_internal_static; #if FOLLOW_X_FORWARDED_FOR - int acl_uses_indirect_client; - int delay_pool_uses_indirect_client; - int log_uses_indirect_client; + int acl_uses_indirect_client; + int delay_pool_uses_indirect_client; + int log_uses_indirect_client; #if LINUX_NETFILTER - int tproxy_uses_indirect_client; + int tproxy_uses_indirect_client; #endif #endif /* FOLLOW_X_FORWARDED_FOR */ - int WIN32_IpAddrChangeMonitor; - int memory_cache_first; - int memory_cache_disk; - int hostStrictVerify; - int client_dst_passthru; - } onoff; - - int forward_max_tries; - int connect_retries; - - class ACL *aclList; - - struct { - acl_access *http; - acl_access *adapted_http; - acl_access *icp; - acl_access *miss; - acl_access *NeverDirect; - acl_access *AlwaysDirect; - acl_access *ASlists; - acl_access *noCache; - acl_access *log; + int WIN32_IpAddrChangeMonitor; + int memory_cache_first; + int memory_cache_disk; + int hostStrictVerify; + int client_dst_passthru; + } onoff; + + int forward_max_tries; + int connect_retries; + + class ACL *aclList; + + struct { + acl_access *http; + acl_access *adapted_http; + acl_access *icp; + acl_access *miss; + acl_access *NeverDirect; + acl_access *AlwaysDirect; + acl_access *ASlists; + acl_access *noCache; + acl_access *log; #if SQUID_SNMP - acl_access *snmp; + acl_access *snmp; #endif #if USE_HTTP_VIOLATIONS - acl_access *brokenPosts; + acl_access *brokenPosts; #endif - acl_access *redirector; - acl_access *reply; - AclAddress *outgoing_address; + acl_access *redirector; + acl_access *store_id; + acl_access *reply; + AclAddress *outgoing_address; #if USE_HTCP - acl_access *htcp; - acl_access *htcp_clr; + acl_access *htcp; + acl_access *htcp_clr; #endif #if USE_SSL - acl_access *ssl_bump; + acl_access *ssl_bump; #endif #if FOLLOW_X_FORWARDED_FOR - acl_access *followXFF; + acl_access *followXFF; #endif /* FOLLOW_X_FORWARDED_FOR */ #if ICAP_CLIENT - acl_access* icap; + acl_access* icap; #endif - } accessList; - AclDenyInfoList *denyInfoList; + } accessList; + AclDenyInfoList *denyInfoList; - struct { - size_t list_width; - int list_wrap; - char *anon_user; - int passive; - int epsv_all; - int epsv; - int eprt; - int sanitycheck; - int telnet; - } Ftp; - RefreshPattern *Refresh; - - struct _cacheSwap { - RefCount *swapDirs; - int n_allocated; - int n_configured; - /// number of disk processes required to support all cache_dirs - int n_strands; - } cacheSwap; - /* - * I'm sick of having to keep doing this .. - */ + struct { + size_t list_width; + int list_wrap; + char *anon_user; + int passive; + int epsv_all; + int epsv; + int eprt; + int sanitycheck; + int telnet; + } Ftp; + RefreshPattern *Refresh; + + struct _cacheSwap { + RefCount *swapDirs; + int n_allocated; + int n_configured; + /// number of disk processes required to support all cache_dirs + int n_strands; + } cacheSwap; + /* + * I'm sick of having to keep doing this .. + */ #define INDEXSD(i) (Config.cacheSwap.swapDirs[(i)].getRaw()) - struct { - char *directory; - int use_short_names; - } icons; - char *errorDirectory; + struct { + char *directory; + int use_short_names; + } icons; + char *errorDirectory; #if USE_ERR_LOCALES - char *errorDefaultLanguage; - int errorLogMissingLanguages; + char *errorDefaultLanguage; + int errorLogMissingLanguages; #endif - char *errorStylesheet; + char *errorStylesheet; - struct { - int onerror; - } retry; - - struct { - int64_t limit; - } MemPools; + struct { + int onerror; + } retry; + + struct { + int64_t limit; + } MemPools; #if USE_DELAY_POOLS - DelayConfig Delay; - ClientDelayConfig ClientDelay; + DelayConfig Delay; + ClientDelayConfig ClientDelay; #endif - struct { - struct { - int average; - int min_poll; - } dns, udp, tcp; - } comm_incoming; - int max_open_disk_fds; - int uri_whitespace; - AclSizeLimit *rangeOffsetLimit; + struct { + struct { + int average; + int min_poll; + } dns, udp, tcp; + } comm_incoming; + int max_open_disk_fds; + int uri_whitespace; + AclSizeLimit *rangeOffsetLimit; #if MULTICAST_MISS_STREAM - struct { + struct { - Ip::Address addr; - int ttl; - unsigned short port; - char *encode_key; - } mcast_miss; -#endif - - /// request_header_access and request_header_replace - HeaderManglers *request_header_access; - /// reply_header_access and reply_header_replace - HeaderManglers *reply_header_access; - ///request_header_add access list - HeaderWithAclList *request_header_add; - ///note - Notes notes; - char *coredump_dir; - char *chroot_dir; + Ip::Address addr; + int ttl; + unsigned short port; + char *encode_key; + }mcast_miss; +#endif + + /// request_header_access and request_header_replace + HeaderManglers *request_header_access; + /// reply_header_access and reply_header_replace + HeaderManglers *reply_header_access; + ///request_header_add access list + HeaderWithAclList *request_header_add; + ///note + Notes notes; + char *coredump_dir; + char *chroot_dir; #if USE_CACHE_DIGESTS - struct { - int bits_per_entry; - time_t rebuild_period; - time_t rewrite_period; - size_t swapout_chunk_size; - int rebuild_chunk_percentage; - } digest; + struct { + int bits_per_entry; + time_t rebuild_period; + time_t rewrite_period; + size_t swapout_chunk_size; + int rebuild_chunk_percentage; + }digest; #endif #if USE_SSL - struct { - int unclean_shutdown; - char *ssl_engine; - } SSL; -#endif - - wordlist *ext_methods; - - struct { - int high_rptm; - int high_pf; - size_t high_memory; - } warnings; - char *store_dir_select_algorithm; - int sleep_after_fork; /* microseconds */ - time_t minimum_expiry_time; /* seconds */ - external_acl *externalAclHelperList; + struct { + int unclean_shutdown; + char *ssl_engine; + }SSL; +#endif + + wordlist *ext_methods; + + struct { + int high_rptm; + int high_pf; + size_t high_memory; + } warnings; + char *store_dir_select_algorithm; + int sleep_after_fork; /* microseconds */ + time_t minimum_expiry_time; /* seconds */ + external_acl *externalAclHelperList; #if USE_SSL - struct { - char *cert; - char *key; - int version; - char *options; - char *cipher; - char *cafile; - char *capath; - char *crlfile; - char *flags; - acl_access *cert_error; - SSL_CTX *sslContext; - sslproxy_cert_sign *cert_sign; - sslproxy_cert_adapt *cert_adapt; - } ssl_client; -#endif - - char *accept_filter; - int umask; - int max_filedescriptors; - int workers; - CpuAffinityMap *cpuAffinityMap; + struct { + char *cert; + char *key; + int version; + char *options; + char *cipher; + char *cafile; + char *capath; + char *crlfile; + char *flags; + acl_access *cert_error; + SSL_CTX *sslContext; + sslproxy_cert_sign *cert_sign; + sslproxy_cert_adapt *cert_adapt; + }ssl_client; +#endif + + char *accept_filter; + int umask; + int max_filedescriptors; + int workers; + CpuAffinityMap *cpuAffinityMap; #if USE_LOADABLE_MODULES - wordlist *loadable_module_names; + wordlist *loadable_module_names; #endif - int client_ip_max_connections; + int client_ip_max_connections; - struct { - int v4_first; ///< Place IPv4 first in the order of DNS results. - ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies. - } dns; + struct { + int v4_first; ///< Place IPv4 first in the order of DNS results. + ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies. + } dns; }; extern SquidConfig Config; -class SquidConfig2 -{ +class SquidConfig2 { public: - struct { - int enable_purge; - int mangle_request_headers; - } onoff; - uid_t effectiveUserID; - gid_t effectiveGroupID; + struct { + int enable_purge; + int mangle_request_headers; + } onoff; + uid_t effectiveUserID; + gid_t effectiveGroupID; }; extern SquidConfig2 Config2; #endif /* SQUID_SQUIDCONFIG_H_ */ === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-11-17 12:58:59 +0000 +++ src/cache_cf.cc 2012-12-02 12:32:19 +0000 @@ -684,40 +684,47 @@ Config.onoff.announce = 0; } if (Config.onoff.httpd_suppress_version_string) visible_appname_string = (char *)appname_string; else visible_appname_string = (char const *)APP_FULLNAME; #if USE_DNSHELPER if (Config.dnsChildren.n_max < 1) fatal("No DNS helpers allocated"); #endif if (Config.Program.redirect) { if (Config.redirectChildren.n_max < 1) { Config.redirectChildren.n_max = 0; wordlistDestroy(&Config.Program.redirect); } } + if (Config.Program.store_id) { + if (Config.storeIdChildren.n_max < 1) { + Config.storeIdChildren.n_max = 0; + wordlistDestroy(&Config.Program.store_id); + } + } + if (Config.appendDomain) if (*Config.appendDomain != '.') fatal("append_domain must begin with a '.'"); if (Config.errHtmlText == NULL) Config.errHtmlText = xstrdup(null_string); #if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE) if (Config.max_filedescriptors > 0) { debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing."); } #elif USE_SELECT || USE_SELECT_WIN32 if (Config.max_filedescriptors > FD_SETSIZE) { debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm."); } #endif storeConfigure(); snprintf(ThisCache, sizeof(ThisCache), "%s (%s)", @@ -746,40 +753,43 @@ else Config.appendDomainLen = 0; if (Config.connect_retries > 10) { debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10."); Config.connect_retries = 10; } requirePathnameExists("MIME Config Table", Config.mimeTablePathname); #if USE_DNSHELPER requirePathnameExists("cache_dns_program", Config.Program.dnsserver); #endif #if USE_UNLINKD requirePathnameExists("unlinkd_program", Config.Program.unlinkd); #endif requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon); if (Config.Program.redirect) requirePathnameExists("redirect_program", Config.Program.redirect->key); + if (Config.Program.store_id) + requirePathnameExists("store_id_program", Config.Program.store_id->key); + requirePathnameExists("Icon Directory", Config.icons.directory); if (Config.errorDirectory) requirePathnameExists("Error Directory", Config.errorDirectory); #if USE_HTTP_VIOLATIONS { const RefreshPattern *R; for (R = Config.Refresh; R; R = R->next) { if (!R->flags.override_expire) continue; debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP"); break; } for (R = Config.Refresh; R; R = R->next) { === modified file 'src/cf.data.pre' --- src/cf.data.pre 2012-11-11 05:10:59 +0000 +++ src/cf.data.pre 2012-12-02 12:51:18 +0000 @@ -4263,40 +4263,178 @@ See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details. DOC_END NAME: url_rewrite_bypass redirector_bypass TYPE: onoff LOC: Config.onoff.redirector_bypass DEFAULT: off DOC_START When this is 'on', a request will not go through the redirector if all redirectors are busy. If this is 'off' and the redirector queue grows too large, Squid will exit with a FATAL error and ask you to increase the number of redirectors. You should only enable this if the redirectors are not critical to your caching system. If you use redirectors for access control, and you enable this option, users may have access to pages they should not be allowed to request. DOC_END COMMENT_START + OPTIONS FOR STORE ID + ----------------------------------------------------------------------------- +COMMENT_END + +NAME: store_id_program store_url_program +TYPE: wordlist +LOC: Config.Program.store_id +DEFAULT: none +DOC_START + Specify the location of the executable URL rewriter to use. + Since they can perform almost any function there isn't one included. + + For each requested URL, the rewriter will receive on line with the format + + [channel-ID ] URL client_ip "/" fqdn user method [ kv-pairs] + + + After processing the request the helper must reply using the following format: + + [channel-ID ] result [ kv-pairs] + + The result code can be: + + OK status=30N url="..." + Redirect the URL to the one supplied in 'url='. + 'status=' is optional and contains the status code to send + the client in Squids HTTP response. It must be one of the + HTTP redirect status codes: 301, 302, 303, 307, 308. + When no status is given Squid will use 302. + + OK rewrite-url="..." + Rewrite the URL to the one supplied in 'rewrite-url='. + The new URL is fetched directly by Squid and returned to + the client as the response to its request. + + ERR + Do not change the URL. + + BH + An internal error occured in the helper, preventing + a result being identified. + + + In the future, the interface protocol will be extended with + key=value pairs ("kv-pairs" shown above). Helper programs + should be prepared to receive and possibly ignore additional + whitespace-separated tokens on each input line. + + When using the concurrency= option the protocol is changed by + introducing a query channel tag in front of the request/response. + The query channel tag is a number between 0 and concurrency-1. + This value must be echoed back unchanged to Squid as the first part + of the response relating to its request. + + WARNING: URL re-writing ability should be avoided whenever possible. + Use the URL redirect form of response instead. + + Re-write creates a difference in the state held by the client + and server. Possibly causing confusion when the server response + contains snippets of its view state. Embeded URLs, response + and content Location headers, etc. are not re-written by this + interface. + + By default, a URL rewriter is not used. +DOC_END + +NAME: store_id_children store_url_children +TYPE: HelperChildConfig +DEFAULT: 20 startup=0 idle=1 concurrency=0 +LOC: Config.storeIdChildren +DOC_START + The maximum number of redirector processes to spawn. If you limit + it too few Squid will have to wait for them to process a backlog of + URLs, slowing it down. If you allow too many they will use RAM + and other system resources noticably. + + The startup= and idle= options allow some measure of skew in your + tuning. + + startup= + + Sets a minimum of how many processes are to be spawned when Squid + starts or reconfigures. When set to zero the first request will + cause spawning of the first child process to handle it. + + Starting too few will cause an initial slowdown in traffic as Squid + attempts to simultaneously spawn enough processes to cope. + + idle= + + Sets a minimum of how many processes Squid is to try and keep available + at all times. When traffic begins to rise above what the existing + processes can handle this many more will be spawned up to the maximum + configured. A minimum setting of 1 is required. + + concurrency= + + The number of requests each redirector helper can handle in + parallel. Defaults to 0 which indicates the redirector + is a old-style single threaded redirector. + + When this directive is set to a value >= 1 then the protocol + used to communicate with the helper is modified to include + a request ID in front of the request/response. The request + ID from the request must be echoed back with the response + to that request. +DOC_END + +NAME: store_id_access store_url_access +TYPE: acl_access +DEFAULT: none +LOC: Config.accessList.store_id +DOC_START + If defined, this access list specifies which requests are + sent to the redirector processes. By default all requests + are sent. + + This clause supports both fast and slow acl types. + See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details. +DOC_END + +NAME: store_id_bypass store_url_bypass +TYPE: onoff +LOC: Config.onoff.store_id_bypass +DEFAULT: off +DOC_START + When this is 'on', a request will not go through the + redirector if all redirectors are busy. If this is 'off' + and the redirector queue grows too large, Squid will exit + with a FATAL error and ask you to increase the number of + redirectors. You should only enable this if the redirectors + are not critical to your caching system. If you use + redirectors for access control, and you enable this option, + users may have access to pages they should not + be allowed to request. +DOC_END + +COMMENT_START OPTIONS FOR TUNING THE CACHE ----------------------------------------------------------------------------- COMMENT_END NAME: cache no_cache TYPE: acl_access DEFAULT: none LOC: Config.accessList.noCache DOC_START A list of ACL elements which, if matched and denied, cause the request to not be satisfied from the cache and the reply to not be cached. In other words, use this to force certain objects to never be cached. You must use the words 'allow' or 'deny' to indicate whether items matching the ACL should be allowed or denied into the cache. Default is to allow all to be cached. This clause supports both fast and slow acl types. See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details. === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2012-11-12 02:25:12 +0000 +++ src/client_side_reply.cc 2012-12-02 11:19:33 +0000 @@ -780,41 +780,44 @@ // TODO: can we use purgeAllCached() here instead of doing the // getPublicByRequestMethod() dance? StoreEntry::getPublicByRequestMethod(this, http->request, Http::METHOD_GET); } // Purges all entries with a given url // TODO: move to SideAgent parent, when we have one /* * We probably cannot purge Vary-affected responses because their MD5 * keys depend on vary headers. */ void purgeEntriesByUrl(HttpRequest * req, const char *url) { #if USE_HTCP bool get_or_head_sent = false; #endif for (HttpRequestMethod m(Http::METHOD_NONE); m != Http::METHOD_ENUM_END; ++m) { if (m.respMaybeCacheable()) { - if (StoreEntry *entry = storeGetPublic(url, m)) { + /* TODO: fix things to allow store_id requests to be deleted. + * is it the place? + */ + if (StoreEntry *entry = storeGetPublic(url, m)) { debugs(88, 5, "purging " << RequestMethodStr(m) << ' ' << url); #if USE_HTCP neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION); if (m == Http::METHOD_GET || m == Http::METHOD_HEAD) { get_or_head_sent = true; } #endif entry->release(); } } } #if USE_HTCP if (!get_or_head_sent) { neighborsHtcpClear(NULL, url, req, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_INVALIDATION); } #endif } void @@ -2143,41 +2146,47 @@ holdingBuffer = result; processReplyAccess(); return; } /* Using this breaks the client layering just a little! */ void clientReplyContext::createStoreEntry(const HttpRequestMethod& m, RequestFlags reqFlags) { assert(http != NULL); /* * For erroneous requests, we might not have a h->request, * so make a fake one. */ if (http->request == NULL) http->request = HTTPMSGLOCK(new HttpRequest(m, AnyP::PROTO_NONE, null_string)); - StoreEntry *e = storeCreateEntry(http->uri, http->log_uri, reqFlags, m); + const char *url; + if (http->request->store_id) + url = http->request->store_id; + else + url = http->uri; + + StoreEntry *e = storeCreateEntry(url, http->log_uri, reqFlags, m); sc = storeClientListAdd(e, this); #if USE_DELAY_POOLS sc->setDelayId(DelayId::DelayClient(http)); #endif reqofs = 0; reqsize = 0; /* I don't think this is actually needed! -- adrian */ /* http->reqbuf = http->norm_reqbuf; */ // assert(http->reqbuf == http->norm_reqbuf); /* The next line is illegal because we don't know if the client stream * buffers have been set up */ // storeClientCopy(http->sc, e, 0, HTTP_REQBUF_SZ, http->reqbuf, // SendMoreData, this); /* So, we mark the store logic as complete */ === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2012-12-01 01:20:32 +0000 +++ src/client_side_request.cc 2012-12-02 13:28:32 +0000 @@ -115,65 +115,68 @@ ClientRequestContext *result = cbdataAlloc(ClientRequestContext); return result; } void ClientRequestContext::operator delete (void *address) { ClientRequestContext *t = static_cast(address); cbdataFree(t); } /* Local functions */ /* other */ static void clientAccessCheckDoneWrapper(allow_t, void *); #if USE_SSL static void sslBumpAccessCheckDoneWrapper(allow_t, void *); #endif static int clientHierarchical(ClientHttpRequest * http); static void clientInterpretRequestHeaders(ClientHttpRequest * http); static HLPCB clientRedirectDoneWrapper; +static HLPCB clientStoreIdDoneWrapper; static void checkNoCacheDoneWrapper(allow_t, void *); SQUIDCEXTERN CSR clientGetMoreData; SQUIDCEXTERN CSS clientReplyStatus; SQUIDCEXTERN CSD clientReplyDetach; static void checkFailureRatio(err_type, hier_code); ClientRequestContext::~ClientRequestContext() { /* * Release our "lock" on our parent, ClientHttpRequest, if we * still have one */ if (http) cbdataReferenceDone(http); delete error; debugs(85,3, HERE << this << " ClientRequestContext destructed"); } -ClientRequestContext::ClientRequestContext(ClientHttpRequest *anHttp) : http(cbdataReference(anHttp)), acl_checklist (NULL), redirect_state (REDIRECT_NONE), error(NULL), readNextRequest(false) +ClientRequestContext::ClientRequestContext(ClientHttpRequest *anHttp) : http(cbdataReference(anHttp)), acl_checklist (NULL), redirect_state (REDIRECT_NONE), store_id_state (REDIRECT_NONE), error(NULL), readNextRequest(false) { http_access_done = false; redirect_done = false; redirect_fail_count = 0; + store_id_done = false; + redirect_fail_count = 0; no_cache_done = false; interpreted_req_hdrs = false; #if USE_SSL sslBumpCheckDone = false; #endif debugs(85,3, HERE << this << " ClientRequestContext constructed"); } CBDATA_CLASS_INIT(ClientHttpRequest); void * ClientHttpRequest::operator new (size_t size) { assert (size == sizeof (ClientHttpRequest)); CBDATA_INIT_TYPE(ClientHttpRequest); ClientHttpRequest *result = cbdataAlloc(ClientHttpRequest); return result; } void @@ -903,40 +906,67 @@ if (answer == ACCESS_ALLOWED) redirectStart(http, clientRedirectDoneWrapper, context); else { HelperReply nilReply; context->clientRedirectDone(nilReply); } } void ClientRequestContext::clientRedirectStart() { debugs(33, 5, HERE << "'" << http->uri << "'"); if (Config.accessList.redirector) { acl_checklist = clientAclChecklistCreate(Config.accessList.redirector, http); acl_checklist->nonBlockingCheck(clientRedirectAccessCheckDone, this); } else redirectStart(http, clientRedirectDoneWrapper, this); } +static void +clientStoreIdAccessCheckDone(allow_t answer, void *data) +{ + ClientRequestContext *context = (ClientRequestContext *)data; + ClientHttpRequest *http = context->http; + context->acl_checklist = NULL; + + if (answer == ACCESS_ALLOWED) + redirectStart(http, clientStoreIdDoneWrapper, context); + else { + HelperReply nilReply; + context->clientStoreIdDone(nilReply); + } +} + +void +ClientRequestContext::clientStoreIdStart() +{ + debugs(33, 5, HERE << "'" << http->uri << "'"); + + if (Config.accessList.store_id) { + acl_checklist = clientAclChecklistCreate(Config.accessList.store_id, http); + acl_checklist->nonBlockingCheck(clientStoreIdAccessCheckDone, this); + } else + redirectStart(http, clientStoreIdDoneWrapper, this); +} + static int clientHierarchical(ClientHttpRequest * http) { const char *url = http->uri; HttpRequest *request = http->request; HttpRequestMethod method = request->method; const wordlist *p = NULL; // intercepted requests MUST NOT (yet) be sent to peers unless verified if (!request->flags.hostVerified && (request->flags.intercepted || request->flags.spoofClientIp)) return 0; /* * IMS needs a private key, so we can use the hierarchy for IMS only if our * neighbors support private keys */ if (request->flags.ims && !neighbors_do_private_keys) return 0; @@ -1236,41 +1266,41 @@ // #1: redirect with a specific status code OK status=NNN url="..." // #2: redirect with a default status code OK url="..." // #3: re-write the URL OK rewrite-url="..." Note::Pointer statusNote = reply.notes.find("status"); Note::Pointer urlNote = reply.notes.find("url"); if (urlNote != NULL) { // HTTP protocol redirect to be done. // TODO: change default redirect status for appropriate requests // Squid defaults to 302 status for now for better compatibility with old clients. // HTTP/1.0 client should get 302 (HTTP_MOVED_TEMPORARILY) // HTTP/1.1 client contacting reverse-proxy should get 307 (HTTP_TEMPORARY_REDIRECT) // HTTP/1.1 client being diverted by forward-proxy should get 303 (HTTP_SEE_OTHER) http_status status = HTTP_MOVED_TEMPORARILY; if (statusNote != NULL) { const char * result = statusNote->firstValue(); status = (http_status) atoi(result); } - + /* not needed for store url*/ if (status == HTTP_MOVED_PERMANENTLY || status == HTTP_MOVED_TEMPORARILY || status == HTTP_SEE_OTHER || status == HTTP_PERMANENT_REDIRECT || status == HTTP_TEMPORARY_REDIRECT) { http->redirect.status = status; http->redirect.location = xstrdup(urlNote->firstValue()); // TODO: validate the URL produced here is RFC 2616 compliant absolute URI } else { debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid " << status << " redirect Location: " << urlNote->firstValue()); } } else { // URL-rewrite wanted. Ew. urlNote = reply.notes.find("rewrite-url"); // prevent broken helpers causing too much damage. If old URL == new URL skip the re-write. if (urlNote != NULL && strcmp(urlNote->firstValue(), http->uri)) { // XXX: validate the URL properly *without* generating a whole new request object right here. // XXX: the clone() should be done only AFTER we know the new URL is valid. HttpRequest *new_request = old_request->clone(); @@ -1296,40 +1326,103 @@ debugs(85, DBG_CRITICAL, "ERROR: URL-rewrite produces invalid request: " << old_request->method << " " << urlNote->firstValue() << " " << old_request->http_ver); delete new_request; } } } } break; } /* FIXME PIPELINE: This is innacurate during pipelining */ if (http->getConn() != NULL && Comm::IsConnOpen(http->getConn()->clientConnection)) fd_note(http->getConn()->clientConnection->fd, http->uri); assert(http->uri); http->doCallouts(); } +void +clientStoreIdDoneWrapper(void *data, const HelperReply &result) +{ + ClientRequestContext *calloutContext = (ClientRequestContext *)data; + + if (!calloutContext->httpStateIsValid()) + return; + + calloutContext->clientStoreIdDone(result); +} + +void +ClientRequestContext::clientStoreIdDone(const HelperReply &reply) +{ + HttpRequest *old_request = http->request; + debugs(85, 5, "'" << http->uri << "' result=" << reply); + assert(store_id_state == REDIRECT_PENDING); + store_id_state = REDIRECT_DONE; + + // copy the helper response Notes to the HTTP request for logging + // do it early to ensure that no matter what the outcome the notes are present. + // TODO put them straight into the transaction state record (ALE?) eventually + if (!old_request->helperNotes) + old_request->helperNotes = new Notes; + old_request->helperNotes->add(reply.notes); + + switch(reply.result) { + case HelperReply::Unknown: + case HelperReply::TT: + // Handler in redirect.cc should have already mapped Unknown + // IF it contained valid entry for the old URL-rewrite helper protocol + debugs(85, DBG_IMPORTANT, "ERROR: store-URL helper returned invalid result code. Wrong helper? " << reply); + break; + + case HelperReply::BrokenHelper: + debugs(85, DBG_IMPORTANT, "ERROR: store-URL helper: " << reply << ", attempt #" << (store_id_fail_count+1) << " of 2"); + if (store_id_fail_count < 2) { // XXX: make this configurable ? + ++store_id_fail_count; + // reset state flag to try redirector again from scratch. + store_id_done = false; + } + break; + + case HelperReply::Error: + // no change to be done. + break; + + case HelperReply::Okay: { + Note::Pointer urlNote = reply.notes.find("store-id"); + + // prevent broken helpers causing too much damage. If old URL == new URL skip the re-write. + if (urlNote != NULL && strcmp(urlNote->firstValue(), http->uri)) { + + /* storing the result in the HttpRequest */ + http->request->store_id = xstrdup(urlNote->firstValue()); + } + } + break; + } + + http->doCallouts(); +} + /** Test cache allow/deny configuration * Sets flags.cachable=1 if caching is not denied. */ void ClientRequestContext::checkNoCache() { if (Config.accessList.noCache) { acl_checklist = clientAclChecklistCreate(Config.accessList.noCache, http); acl_checklist->nonBlockingCheck(checkNoCacheDoneWrapper, this); } else { /* unless otherwise specified, we try to cache. */ checkNoCacheDone(ACCESS_ALLOWED); } } static void checkNoCacheDoneWrapper(allow_t answer, void *data) { ClientRequestContext *calloutContext = (ClientRequestContext *) data; @@ -1625,40 +1718,52 @@ if (!calloutContext->redirect_done) { calloutContext->redirect_done = true; assert(calloutContext->redirect_state == REDIRECT_NONE); if (Config.Program.redirect) { debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); calloutContext->redirect_state = REDIRECT_PENDING; calloutContext->clientRedirectStart(); return; } } if (!calloutContext->adapted_http_access_done) { debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); calloutContext->adapted_http_access_done = true; calloutContext->clientAccessCheck2(); return; } + if (!calloutContext->store_id_done) { + calloutContext->store_id_done = true; + assert(calloutContext->store_id_state == REDIRECT_NONE); + + if (Config.Program.store_id) { + debugs(83, 3, HERE << "Doing calloutContext->clientStoreIdStart()"); + calloutContext->store_id_state = REDIRECT_PENDING; + calloutContext->clientStoreIdStart(); + return; + } + } + if (!calloutContext->interpreted_req_hdrs) { debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()"); calloutContext->interpreted_req_hdrs = 1; clientInterpretRequestHeaders(this); } if (!calloutContext->no_cache_done) { calloutContext->no_cache_done = true; if (Config.accessList.noCache && request->flags.cachable) { debugs(83, 3, HERE << "Doing calloutContext->checkNoCache()"); calloutContext->checkNoCache(); return; } } } // if !calloutContext->error if (!calloutContext->tosToClientDone) { calloutContext->tosToClientDone = true; if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConnection)) { === modified file 'src/client_side_request.h' --- src/client_side_request.h 2012-11-04 12:27:49 +0000 +++ src/client_side_request.h 2012-12-02 11:04:07 +0000 @@ -80,40 +80,41 @@ bool multipartRangeRequest() const; void processRequest(); void httpStart(); bool onlyIfCached()const; bool gotEnough() const; _SQUID_INLINE_ StoreEntry *storeEntry() const; void storeEntry(StoreEntry *); _SQUID_INLINE_ StoreEntry *loggingEntry() const; void loggingEntry(StoreEntry *); _SQUID_INLINE_ ConnStateData * getConn() const; _SQUID_INLINE_ void setConn(ConnStateData *); /** Details of the client socket which produced us. * Treat as read-only for the lifetime of this HTTP request. */ Comm::ConnectionPointer clientConnection; HttpRequest *request; /* Parsed URL ... */ char *uri; + char *store_id; char *log_uri; struct { int64_t offset; int64_t size; size_t headers_sz; } out; HttpHdrRangeIter range_iter; /* data for iterating thru range specs */ size_t req_sz; /* raw request size on input, not current request size */ log_type logType; struct timeval start_time; AccessLogEntry::Pointer al; ///< access.log entry struct { unsigned int accel:1; unsigned int intercepted:1; unsigned int spoof_client_ip:1; unsigned int internal:1; === modified file 'src/redirect.cc' --- src/redirect.cc 2012-11-30 11:08:47 +0000 +++ src/redirect.cc 2012-12-02 13:47:30 +0000 @@ -51,41 +51,43 @@ #if USE_SSL #include "ssl/support.h" #endif /// url maximum lengh + extra informations passed to redirector #define MAX_REDIRECTOR_REQUEST_STRLEN (MAX_URL + 1024) typedef struct { void *data; char *orig_url; Ip::Address client_addr; const char *client_ident; const char *method_s; HLPCB *handler; } redirectStateData; static HLPCB redirectHandleReply; static void redirectStateFree(redirectStateData * r); static helper *redirectors = NULL; +static helper *storeIds = NULL; static OBJH redirectStats; +static OBJH storeIdStats; static int n_bypassed = 0; CBDATA_TYPE(redirectStateData); static void redirectHandleReply(void *data, const HelperReply &reply) { redirectStateData *r = static_cast(data); debugs(61, 5, HERE << "reply=" << reply); // XXX: This function is now kept only to check for and display the garbage use-case // and to map the old helper response format(s) into new format result code and key=value pairs // it can be removed when the helpers are all updated to the normalized "OK/ERR kv-pairs" format if (reply.result == HelperReply::Unknown) { // BACKWARD COMPATIBILITY 2012-06-15: // Some nasty old helpers send back the entire input line including extra format keys. // This is especially bad for simple perl search-replace filter scripts. // // * trim all but the first word off the response. // * warn once every 50 responses that this will stop being fixed-up soon. @@ -160,40 +162,55 @@ { safe_free(r->orig_url); cbdataFree(r); } static void redirectStats(StoreEntry * sentry) { if (redirectors == NULL) { storeAppendPrintf(sentry, "No redirectors defined\n"); return; } helperStats(sentry, redirectors, "Redirector Statistics"); if (Config.onoff.redirector_bypass) storeAppendPrintf(sentry, "\nNumber of requests bypassed " "because all redirectors were busy: %d\n", n_bypassed); } +static void +storeIdStats(StoreEntry * sentry) +{ + if (storeIds == NULL) { + storeAppendPrintf(sentry, "No StoreIds defined\n"); + return; + } + + helperStats(sentry, storeIds, "StoreIds Statistics"); + + if (Config.onoff.store_id_bypass) + storeAppendPrintf(sentry, "\nNumber of requests bypassed " + "because all store_Ids were busy: %d\n", n_bypassed); +} + /**** PUBLIC FUNCTIONS ****/ void redirectStart(ClientHttpRequest * http, HLPCB * handler, void *data) { ConnStateData * conn = http->getConn(); redirectStateData *r = NULL; const char *fqdn; char buf[MAX_REDIRECTOR_REQUEST_STRLEN]; int sz; http_status status; char claddr[MAX_IPSTRLEN]; char myaddr[MAX_IPSTRLEN]; assert(http); assert(handler); debugs(61, 5, "redirectStart: '" << http->uri << "'"); if (Config.onoff.redirector_bypass && redirectors->stats.queue_size) { /* Skip redirector if there is one request queued */ ++n_bypassed; @@ -281,63 +298,89 @@ #if USE_AUTH http->getConn() != NULL && http->getConn()->auth_user_request != NULL ? http->getConn()->auth_user_request : http->request->auth_user_request); #else NULL); #endif node = (clientStreamNode *)http->client_stream.tail->data; clientStreamRead(node, http, node->readBuffer); return; } debugs(61,6, HERE << "sending '" << buf << "' to the helper"); helperSubmit(redirectors, buf, redirectHandleReply, r); } static void redirectRegisterWithCacheManager(void) { Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1); + Mgr::RegisterAction("store_id", "Store IDs Stats", storeIdStats, 0, 1); } void redirectInit(void) { static int init = 0; redirectRegisterWithCacheManager(); - if (!Config.Program.redirect) - return; + if (!Config.Program.redirect && !Config.Program.store_id) + return; + + if (Config.Program.redirect){ if (redirectors == NULL) - redirectors = new helper("redirector"); + redirectors = new helper("redirector"); - redirectors->cmdline = Config.Program.redirect; + redirectors->cmdline = Config.Program.redirect; - redirectors->childs.updateLimits(Config.redirectChildren); + redirectors->childs.updateLimits(Config.redirectChildren); - redirectors->ipc_type = IPC_STREAM; + redirectors->ipc_type = IPC_STREAM; - helperOpenServers(redirectors); + helperOpenServers(redirectors); + } + + if (Config.Program.store_id){ + + if (storeIds == NULL) + storeIds = new helper("store_id"); + + storeIds->cmdline = Config.Program.store_id; + + storeIds->childs.updateLimits(Config.storeIdChildren); + + storeIds->ipc_type = IPC_STREAM; + + helperOpenServers(storeIds); + } if (!init) { init = 1; CBDATA_INIT_TYPE(redirectStateData); } } void redirectShutdown(void) { - if (!redirectors) + if (!storeIds && !redirectors) return; - helperShutdown(redirectors); + if (redirectors) + helperShutdown(redirectors); + + if (storeIds) + helperShutdown(storeIds); if (!shutting_down) return; delete redirectors; redirectors = NULL; + + delete storeIds; + storeIds = NULL; + } === modified file 'src/store_key_md5.cc' --- src/store_key_md5.cc 2012-09-01 14:38:36 +0000 +++ src/store_key_md5.cc 2012-12-02 11:20:57 +0000 @@ -122,41 +122,41 @@ unsigned char m = (unsigned char) method.id(); SquidMD5_CTX M; SquidMD5Init(&M); SquidMD5Update(&M, &m, sizeof(m)); SquidMD5Update(&M, (unsigned char *) url, strlen(url)); SquidMD5Final(digest, &M); return digest; } const cache_key * storeKeyPublicByRequest(HttpRequest * request) { return storeKeyPublicByRequestMethod(request, request->method); } const cache_key * storeKeyPublicByRequestMethod(HttpRequest * request, const HttpRequestMethod& method) { static cache_key digest[SQUID_MD5_DIGEST_LENGTH]; unsigned char m = (unsigned char) method.id(); - const char *url = urlCanonical(request); + const char *url = request->urlStoreId(); SquidMD5_CTX M; SquidMD5Init(&M); SquidMD5Update(&M, &m, sizeof(m)); SquidMD5Update(&M, (unsigned char *) url, strlen(url)); if (request->vary_headers) SquidMD5Update(&M, (unsigned char *) request->vary_headers, strlen(request->vary_headers)); SquidMD5Final(digest, &M); return digest; } cache_key * storeKeyDup(const cache_key * key) { cache_key *dup = (cache_key *)memAllocate(MEM_MD5_DIGEST); memcpy(dup, key, SQUID_MD5_DIGEST_LENGTH); return dup; }