经过尝试,我感觉目前最方便稳定的方式是开发squid的共享动态库ecap插件,实现自己的目的.
当然你可以修改squid的源代码,但是那样做需要首先研究透彻squid的工作机理,而且需要谨慎的修改,原作者也不建议这样,因为可能会导致squid不稳定.
当然还可以搭建icap服务,但是经过一轮的尝试和摸索一下,发现icap服务软件并没有像apache、nginx、和lighttpd这些成熟稳定的代码可以用,所以放弃,但是不乏一些小巧灵活的python架构的软件,可以使用,进行业务测试倒是可以,真正用于生产环境还是有点不足.
比如:
pyicap(A lightweight python framework for writing ICAP services),简单方便,生产环境不太适合.
bitz-server(An ICAP server implementation in C++ and Python),不太稳定.
yum -y install automake autoconf libtool
mkdir -p /opt/packages
cd /opt/packages
wget http://www.measurement-factory.com/tmp/ecap/ecap_adapter_sample-0.2.0.tar.gz
wget http://www.measurement-factory.com/tmp/ecap/libecap-0.2.0.tar.gz
tar -zxf libecap-0.2.0.tar.gz
cd libecap-0.2.0
./configure
make
make install
wget http://www.squid-cache.org/Versions/v3/3.3/squid-3.3.3.tar.bz2
tar -xf squid-3.3.3.tar.bz2
cd squid-3.3.3
./configure --enable-http-violations --enable-ltdl-convenience --enable-icap-client --enable-ecap --prefix=/usr/local/squid PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
make
make install
问题二,编译插件成功,但是运行squid -NCXd 2命令后报错如下:
FATAL: dying from an unhandled exception: file not found
terminate called after throwing an instance of 'TextException'
what(): file not found
Aborted
解决: 插件在编译连接的问题,重新安装boost库解决.
#include "bbkanba.h"#include "Debugger.h"#include <iostream>#include <algorithm>#include <libecap/common/registry.h>#include <libecap/common/errors.h>#include <libecap/common/message.h>#include <libecap/common/header.h>#include <libecap/common/names.h>#include <libecap/common/named_values.h>#include <libecap/host/host.h>#include <libecap/adapter/service.h>#include <libecap/adapter/xaction.h>#include <libecap/host/xaction.h>#include <boost/network/uri.hpp>#include <boost/network/uri/uri_io.hpp>#include <boost/network/protocol/http/client.hpp>usingnamespaceboost::network;namespaceAdapter{// not required, but adds clarityusinglibecap::size_type;typedeflibecap::RequestLine*CLRLP;classService:publiclibecap::adapter::Service{public:// Aboutvirtualstd::stringuri()const;// unique across all vendorsvirtualstd::stringtag()const;// changes with version and configvirtualvoiddescribe(std::ostream&os)const;// free-format info// Configurationvirtualvoidconfigure(constlibecap::Options&cfg);virtualvoidreconfigure(constlibecap::Options&cfg);// Lifecyclevirtualvoidstart();// expect makeXaction() callsvirtualvoidstop();// no more makeXaction() calls until start()virtualvoidretire();// no more makeXaction() calls// Scope (XXX: this may be changed to look at the whole header)virtualboolwantsUrl(constchar*url)const;// Workvirtuallibecap::adapter::Xaction*makeXaction(libecap::host::Xaction*hostx);};classXaction:publiclibecap::adapter::Xaction{public:Xaction(libecap::shared_ptr<Service>s,libecap::host::Xaction*x);virtual~Xaction();// meta-information for the host transactionvirtualconstlibecap::Areaoption(constlibecap::Name&name)const;virtualvoidvisitEachOption(libecap::NamedValueVisitor&visitor)const;// lifecyclevirtualvoidstart();virtualvoidstop();// adapted body transmission controlvirtualvoidabDiscard();virtualvoidabMake();virtualvoidabMakeMore();virtualvoidabStopMaking();// adapted body content extraction and consumptionvirtuallibecap::AreaabContent(size_typeoffset,size_typesize);virtualvoidabContentShift(size_typesize);// virgin body state notificationvirtualvoidnoteVbContentDone(boolatEnd);virtualvoidnoteVbContentAvailable();// libecap::Callable API, via libecap::host::Xactionvirtualboolcallable()const;protected:voidstopVb();// stops receiving vb (if we are receiving it)voidgetUri(libecap::shared_ptr<libecap::Message>&);voidgoToUrl(std::stringorgUrl,std::stringhost,std::stringstate);voiddebugAction(conststd::string&action,constbool&showOrgUrl=true);libecap::host::Xaction*lastHostCall();// clears hostxprivate:CLRLPrequestLine;libecap::Areauri;// Request-URI from headers, for logginglibecap::shared_ptr<constService>service;// configuration accesslibecap::host::Xaction*hostx;// Host transaction reptypedefenum{opUndecided,opOn,opComplete,opNever}OperationState;typedefenum{localWebServer,normal}OprationAdaptedState;OperationStatereceivingVb;OperationStatesendingAb;OprationAdaptedStateadaptedGotoAction;};staticconststd::stringCfgErrorPrefix="eBBkanba Adapter: configuration error: ";}// namespace Adapterstd::stringAdapter::Service::uri()const{return"ecap://bbkanba.com/bbkanba";}std::stringAdapter::Service::tag()const{returnPACKAGE_VERSION;}voidAdapter::Service::describe(std::ostream&os)const{os<<"A eBBkanba adapter from "<<PACKAGE_NAME<<" v"<<PACKAGE_VERSION;}voidAdapter::Service::configure(constlibecap::Options&cfg){}voidAdapter::Service::reconfigure(constlibecap::Options&cfg){}voidAdapter::Service::start(){libecap::adapter::Service::start();}voidAdapter::Service::stop(){libecap::adapter::Service::stop();}voidAdapter::Service::retire(){libecap::adapter::Service::stop();}boolAdapter::Service::wantsUrl(constchar*url)const{returntrue;// no-op is applied to all messages}libecap::adapter::Xaction*Adapter::Service::makeXaction(libecap::host::Xaction*hostx){returnnewAdapter::Xaction(std::tr1::static_pointer_cast<Service>(self),hostx);}Adapter::Xaction::Xaction(libecap::shared_ptr<Service>aService,libecap::host::Xaction*x):service(aService),hostx(x),receivingVb(opUndecided),sendingAb(opUndecided),adaptedGotoAction(normal){}Adapter::Xaction::~Xaction(){if(libecap::host::Xaction*x=hostx){hostx=0;requestLine=0;x->adaptationAborted();}}constlibecap::AreaAdapter::Xaction::option(constlibecap::Name&)const{returnlibecap::Area();// this transaction has no meta-information}voidAdapter::Xaction::visitEachOption(libecap::NamedValueVisitor&)const{// this transaction has no meta-information to pass to the visitor}voidAdapter::Xaction::start(){Must(hostx);//static int scannerCount = 0;//++scannerCount;//Debugger(ilNormal|flApplication) << "eBBkanba: " << "Initializing eBBkanba engine #" << scannerCount << ".";//查看请求是否包含http头以外的数据if(hostx->virgin().body()){receivingVb=opOn;hostx->vbMake();// ask host to supply virgin body}else{// we are not interested in vb if there is not onereceivingVb=opNever;}//获取用户iplibecap::Header::ValueclientIP=hostx->option(libecap::metaClientIp);/* adapt message header ,copy一份http请求的纯原始副本,然后下面可能会修改内容*/libecap::shared_ptr<libecap::Message>adapted=hostx->virgin().clone();Must(adapted!=0);// delete ContentLength header because we may change the length// unknown length may have performance implications for the host//获取用户请求的urlgetUri(adapted);if(uri.size>0){//adapted->header().removeAny(libecap::headerContentLength);uri::uriurl_path(uri.toString());std::stringurl_path_tolower=url_path.host();std::transform(url_path_tolower.begin(),url_path_tolower.end(),url_path_tolower.begin(),::tolower);if(url_path_tolower!="127.0.0.1"){http::client::responseresponse=http::client().get(http::request("http://127.0.0.1:9090/check.php?uip="+clientIP.toString()));std::stringcheck=static_cast<std::string>(body(response));if(check=="0"){//则表示用户没有经过认证goToUrl(uri.toString(),"http://127.0.0.1:9090","0");}if(check=="1"){//表示已经过期goToUrl(uri.toString(),"http://127.0.0.1:9090","1");}}}// 最后返回我们修改过的用户请求if(!adapted->body()){sendingAb=opNever;// there is nothing to sendlastHostCall()->useAdapted(adapted);}else{hostx->useAdapted(adapted);}}voidAdapter::Xaction::stop(){hostx=0;requestLine=0;}voidAdapter::Xaction::abDiscard(){Must(sendingAb==opUndecided);// have not started yetsendingAb=opNever;// we do not need more vb if the host is not interested in abstopVb();}voidAdapter::Xaction::abMake(){Must(sendingAb==opUndecided);// have not yet started or decided not to sendMust(hostx->virgin().body());// that is our only source of ab content// we are or were receiving vbMust(receivingVb==opOn||receivingVb==opComplete);sendingAb=opOn;hostx->noteAbContentAvailable();}voidAdapter::Xaction::abMakeMore(){Must(receivingVb==opOn);// a precondition for receiving more vbhostx->vbMakeMore();}voidAdapter::Xaction::abStopMaking(){sendingAb=opComplete;// we do not need more vb if the host is not interested in more abstopVb();}libecap::AreaAdapter::Xaction::abContent(size_typeoffset,size_typesize){Must(sendingAb==opOn||sendingAb==opComplete);returnhostx->vbContent(offset,size);}voidAdapter::Xaction::abContentShift(size_typesize){Must(sendingAb==opOn||sendingAb==opComplete);hostx->vbContentShift(size);}voidAdapter::Xaction::noteVbContentDone(boolatEnd){Must(receivingVb==opOn);receivingVb=opComplete;if(sendingAb==opOn){hostx->noteAbContentDone(atEnd);sendingAb=opComplete;}}voidAdapter::Xaction::noteVbContentAvailable(){Must(receivingVb==opOn);if(sendingAb==opOn)hostx->noteAbContentAvailable();}boolAdapter::Xaction::callable()const{returnhostx!=0;// no point to call us if we are done}// tells the host that we are not interested in [more] vb// if the host does not know that alreadyvoidAdapter::Xaction::stopVb(){if(receivingVb==opOn){hostx->vbStopMaking();receivingVb=opComplete;}else{// we already got the entire body or refused it earlierMust(receivingVb!=opUndecided);}}//重新定位请求地址,到用户认证页面,并把用户请求url作为参数传入voidAdapter::Xaction::goToUrl(std::stringorgUrl,std::stringnew_host,std::stringstate){std::stringnew_url_path=new_host+"/?state="+state+"&orgUrl="+orgUrl;constlibecap::Header::Valuenew_url_path_r=libecap::Area::FromTempString(new_url_path);debugAction("new URL: "+new_url_path);requestLine->uri(new_url_path_r);}voidAdapter::Xaction::getUri(libecap::shared_ptr<libecap::Message>&adapted){if(!hostx)return;if((requestLine=dynamic_cast<CLRLP>(&adapted->firstLine())))uri=requestLine->uri();}voidAdapter::Xaction::debugAction(conststd::string&actDescript,constbool&showOrgUrl){std::stringdescipt(actDescript);if(showOrgUrl)descipt+=" ( org URL: "+uri.toString()+" )";Debugger(ilNormal|flApplication)<<"eBBkanba: "<<descipt;}// this method is used to make the last call to hostx transaction// last call may delete adapter transaction if the host no longer needs it// TODO: replace with hostx-independent "done" methodlibecap::host::Xaction*Adapter::Xaction::lastHostCall(){libecap::host::Xaction*x=hostx;Must(x);hostx=0;requestLine=0;returnx;}// create the adapter and register with libecap to reach the host applicationstaticconstboolRegistered=(libecap::RegisterService(newAdapter::Service),true);