Using eCAP with Squid 3.x/4.x

Using eCAP for GZip support with Squid 3.x/4.x

Warning: Any example presented here is provided "as-is" with no support or guarantee of suitability. If you have any further questions about these examples please email the squid-users mailing list.

Outline

Since Squid does not support runtime content compression with GZip, we will be used existing eCAP support and GZip eCAP module.

Usage

This configuration is very useful to reduce external Internet traffic from proxy and good caching compressed data.

Build eCAP library

We are uses two different libraries for different branches of Squid. 0.2.0 for Squid 3.4.x or 1.0.0/1.0.1 for Squid 3.5.x/4.x.x

Build and install library accordingly your Squid 32-bit or 64-bit versions:

## 32-bit GCC
./configure 'CXXFLAGS=-O2 -m32 -pipe' 'CFLAGS=-O2 -m32 -pipe'

## 64-bit GCC
./configure 'CXXFLAGS=-O2 -m64 -pipe' 'CFLAGS=-O2 -m64 -pipe'

gmake
gmake install-strip

Then rebuild your Squid with --enable-ecap configure option. To do that you may need to add PKG_CONFIG_PATH to your configure options:

./configure '--enable-ecap' 'PKG_CONFIG_PATH=/usr/local/lib/pkgconfig'

PKG_CONFIG_PATH pointed to libecap pkgconfig file.

Patch and build squid-ecap-gzip

To build squid-ecap-gzip with corresponding eCAP library, you need apply patch for 0.2.0 or 1.0.0 first.

  • {i} Note: Patch 1.0.0 appropriate also when using libecap 1.0.1.

Then build squid-ecap-gzip:

## 32 bit GCC
./configure 'CXXFLAGS=-O2 -m32 -pipe' 'CFLAGS=-O2 -m32 -pipe' 'LDFLAGS=-L/usr/local/lib'
## 64 bit GCC
./configure 'CXXFLAGS=-O2 -m64 -pipe' 'CFLAGS=-O2 -m64 -pipe' 'LDFLAGS=-L/usr/local/lib'
gmake
gmake install-strip
  • {i} Note: It is important to choose identical 32 or 64 bit (like your Squid) build mode for eCAP library and squid-gzip-ecap.

Squid Configuration File

Paste the configuration file like this:

ecap_enable on
acl HTTP_STATUS_OK http_status 200
loadable_modules /usr/local/lib/ecap_adapter_gzip.so
ecap_service gzip_service respmod_precache ecap://www.vigos.com/ecap_gzip bypass=off
adaptation_access gzip_service allow HTTP_STATUS_OK

Also you can add next lines to your squid.conf:

# Replace Accept-Encoding to support compression via eCAP
request_header_access Accept-Encoding deny all
request_header_replace Accept-Encoding gzip

to adapt Accept-Encoding to set gzip support first.

Finally, restart your Squid and enjoy.

  • {X} Note: Don't specify Accept-Encoding in request_header_replace like this: gzip;q=1.0, identity; q=0.5, *;q=0. This is correct, but Yahoo experienced known problems with this encoding specifications. Also note - identity is default and you do not required to specify it.

Support compression all text/* or extended text content types

To support compression not only text/html, but also all text/* (i.e. text/javascript, text/plain, text/xml, text/css) types you must patch squid-ecap-gzip with this one:

--- src/adapter_gzip.cc 2011-02-13 17:42:20.000000000 +0300
+++ src/adapter_gzip.cc 2012-02-26 03:37:26.000000000 +0400
@@ -353,17 +353,19 @@
 -* At this time, only responses with "text/html" content-type are allowed to be compressed.
 +* At this time, only responses with "text/*" content-type are allowed to be compressed.
 */
 static const libecap::Name contentTypeName("Content-Type");
 -
 +
 // Set default value
 this->requirements.responseContentTypeOk = false;
if(adapted->header().hasAny(contentTypeName)) {
 const libecap::Header::Value contentType = adapted->header().value(contentTypeName);
 -
 + std::string contentTypeType; // store contenttype substr
 +
 if(contentType.size > 0) {
 std::string contentTypeString = contentType.toString(); // expensive
 + contentTypeType = contentTypeString.substr(0,4);
 - if(strstr(contentTypeString.c_str(),"text/html")) {
 + if(strstr(contentTypeType.c_str(),"text")) {
 this->requirements.responseContentTypeOk = true;
 }
 }
  • {i} Note: This is not all possible text types in modern Web. If you want to achieve less disk cache and a bit more delivery speed, you can apply another patch against previous:

--- src/adapter_gzip.cc         Tue Jun 21 03:20:48 2016
+++ src/adapter_gzip.cc         Tue Jun 21 03:24:34 2016
@@ -367,7 +367,6 @@
 
        /**
         * Checks the Content-Type response header.
-        * At this time, only responses with "text/html" content-type are allowed to be compressed.
         */
        static const libecap::Name contentTypeName("Content-Type");
        
@@ -376,13 +375,27 @@
 
        if(adapted->header().hasAny(contentTypeName)) {
                const libecap::Header::Value contentType = adapted->header().value(contentTypeName);
-               
+
+               std::string contentTypeType; // store contenttype substr                
+
                if(contentType.size > 0) {
                        std::string contentTypeString = contentType.toString(); // expensive
-                       
-                       if(strstr(contentTypeString.c_str(),"text/html")) {
+                       contentTypeType = contentTypeString.substr(0,4);                        
+                       if(strstr(contentTypeType.c_str(),"text")) {
                                this->requirements.responseContentTypeOk = true;
                        }
+                       else if(strstr(contentTypeString.c_str(),"application/xml")) {
+                               this->requirements.responseContentTypeOk = true;
+                       }
+                       else if(strstr(contentTypeString.c_str(),"application/javascript")) {
+                               this->requirements.responseContentTypeOk = true;
+                       }
+                       else if(strstr(contentTypeString.c_str(),"application/x-javascript")) {
+                               this->requirements.responseContentTypeOk = true;
+                       }
+                       else if(strstr(contentTypeString.c_str(),"application/x-protobuffer")) {
+                               this->requirements.responseContentTypeOk = true;
+                       }
                }
        }
 
@@ -410,7 +423,7 @@
        adapted->header().add(name, value);
        
 
-       // Add "Vary: Accept-Encoding" response header if Content-Type is "text/html"
+       // Add "Vary: Accept-Encoding" response header if Content-Type is supported type
        if(requirements.responseContentTypeOk) {
                static const libecap::Name varyName("Vary");
                const libecap::Header::Value varyValue = libecap::Area::FromTempString("Accept-Encoding");

After applying this patch has the meaning to change access to adapter as follows:

ecap_enable on
acl HTTP_STATUS_OK http_status 200
loadable_modules /usr/local/lib/ecap_adapter_gzip.so
ecap_service gzip_service respmod_precache ecap://www.vigos.com/ecap_gzip bypass=off
acl allowedmime rep_mime_type -i (text\/|javascript|xml|application\/x-protobuffer)
adaptation_access gzip_service allow allowedmime
adaptation_access gzip_service allow HTTP_STATUS_OK

to prevent adapter overloading with unsupported types.

  • {X} Note: To prevent possible memory leaking during adapter running, you can also use this patch:

--- src/adapter_gzip.cc         Wed Jun  8 21:21:10 2016
+++ src/adapter_gzip.cc         Sat Jun 18 22:32:09 2016
@@ -548,7 +548,7 @@
        
 
        Must(receivingVb == opOn);
-       receivingVb = opComplete;
+       stopVb();
        if (sendingAb == opOn) {
                hostx->noteAbContentDone(atEnd);
                sendingAb = opComplete;
@@ -611,7 +611,7 @@
 // if the host does not know that already
 void Adapter::Xaction::stopVb() {
        if (receivingVb == opOn) {
-               hostx->vbStopMaking();
+               hostx->vbStopMaking(); // we will not call vbContent() any more
                receivingVb = opComplete;
        } else {
                // we already got the entire body or refused it earlier

This patch is based on original Alex Rousskov patch from here.

Using eCAP for antivirus checking with Squid 3.x/4.x

Outline

Using eCAP for antivirus checking, like C-ICAP, may be more effective. You avoiding usage intermediate services (C-ICAP and clamd itself, module uses libclamav), and, therefore, can do antivirus checking more quickly. This is reduces total Squid installation latency and memory consumption as a whole.

Build eCAP ClamAV adapter

First you need to download eCAP ClamAV adapter from here.

Then you need to compile and install adapter:

## 32 bit GCC
./configure 'CXXFLAGS=-O3 -m32 -pipe' 'CFLAGS=-O3 -m32 -pipe' 'LDFLAGS=-L/usr/local/lib' PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/clamav/lib/pkgconfig 'CPPFLAGS=-I/usr/local/clamav/include -I/usr/include' 'LDFLAGS=-L/usr/local/lib -L/usr/local/clamav/lib'
## 64 bit GCC
./configure 'CXXFLAGS=-O3 -m64 -pipe' 'CFLAGS=-O3 -m64 -pipe' 'LDFLAGS=-L/usr/local/lib' PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/clamav/lib/pkgconfig 'CPPFLAGS=-I/usr/local/clamav/include -I/usr/include' 'LDFLAGS=-L/usr/local/lib -L/usr/local/clamav/lib/amd64'
gmake
gmake install-strip
  • {i} Note: To use adapter with 64-bit Squid, you need also to compile ClamAV and libecap also with 64 bit. Also use appropriate adapter version for interoperability with your Squid version and used libecap.

  • {i} Note: On some platforms (i.e. Solaris) you may need to add #include <unistd.h> to src/Gadgets.h to avoid compilation error due to lack of unlink subroutine.

Squid Configuration File

Paste the configuration file like this:

ecap_enable on

# Bypass scan mime-types
acl bypass_scan_types_req req_mime_type -i ^text/
acl bypass_scan_types_req req_mime_type -i ^application/x-javascript
acl bypass_scan_types_req req_mime_type -i ^application/x-shockwave-flash
acl bypass_scan_types_req req_mime_type -i ^image/
acl bypass_scan_types_req req_mime_type -i ^video
acl bypass_scan_types_req req_mime_type -i ^audio
acl bypass_scan_types_req req_mime_type -i ^.*application\/x-mms-framed.*$

acl bypass_scan_types_rep rep_mime_type -i ^text/
acl bypass_scan_types_rep rep_mime_type -i ^application/x-javascript
acl bypass_scan_types_rep rep_mime_type -i ^application/x-shockwave-flash
acl bypass_scan_types_rep rep_mime_type -i ^image/
acl bypass_scan_types_rep rep_mime_type -i ^video
acl bypass_scan_types_rep rep_mime_type -i ^audio
acl bypass_scan_types_rep rep_mime_type -i ^.*application\/x-mms-framed.*$

loadable_modules /usr/local/lib/ecap_clamav_adapter.so
ecap_service clamav_service_req reqmod_precache uri=ecap://e-cap.org/ecap/services/clamav?mode=REQMOD bypass=off
ecap_service clamav_service_resp respmod_precache uri=ecap://e-cap.org/ecap/services/clamav?mode=RESPMOD bypass=on
adaptation_access clamav_service_req allow !bypass_scan_types_req all
adaptation_access clamav_service_resp allow !bypass_scan_types_rep all
  • {X} Note: On some setups you may need to create symbolic link in $prefix/clamav/share to DatabaseDirectory path, specified in clamd.conf. I.e, for example:

ln -s /var/lib/clamav /usr/local/clamav/share/clamav

This is due to semi-hardcoded db path in libclamav. Otherwise adaptation module will be crash Squid itself in current releases.

Co-existing both services in one setup

Both services can co-exists in one squid instance:

ecap_enable on

# Bypass scan mime-types
acl bypass_scan_types_req req_mime_type -i ^text/
acl bypass_scan_types_req req_mime_type -i ^application/x-javascript
acl bypass_scan_types_req req_mime_type -i ^application/x-shockwave-flash
acl bypass_scan_types_req req_mime_type -i ^image/
acl bypass_scan_types_req req_mime_type -i ^video
acl bypass_scan_types_req req_mime_type -i ^audio
acl bypass_scan_types_req req_mime_type -i ^.*application\/x-mms-framed.*$

acl bypass_scan_types_rep rep_mime_type -i ^text/
acl bypass_scan_types_rep rep_mime_type -i ^application/x-javascript
acl bypass_scan_types_rep rep_mime_type -i ^application/x-shockwave-flash
acl bypass_scan_types_rep rep_mime_type -i ^image/
acl bypass_scan_types_rep rep_mime_type -i ^video
acl bypass_scan_types_rep rep_mime_type -i ^audio
acl bypass_scan_types_rep rep_mime_type -i ^.*application\/x-mms-framed.*$

loadable_modules /usr/local/lib/ecap_clamav_adapter.so
ecap_service clamav_service_req reqmod_precache uri=ecap://e-cap.org/ecap/services/clamav?mode=REQMOD bypass=off
ecap_service clamav_service_resp respmod_precache uri=ecap://e-cap.org/ecap/services/clamav?mode=RESPMOD bypass=on
adaptation_access clamav_service_req allow !bypass_scan_types_req all
adaptation_access clamav_service_resp allow !bypass_scan_types_rep all

acl HTTP_STATUS_OK http_status 200
loadable_modules /usr/local/lib/ecap_adapter_gzip.so
ecap_service gzip_service respmod_precache ecap://www.vigos.com/ecap_gzip bypass=off
adaptation_access gzip_service allow HTTP_STATUS_OK

{X} BEWARE: Order is important! eCAP ClamAV adapter should precede Vigos adapter!

ConfigExamples/ContentAdaptation/eCAP (last edited 2016-07-10 10:21:15 by YuriVoinov)