Tải bản đầy đủ

OReilly writing apache modules with perl and c apr 1999 ISBN 156592567x

10.5TheTableAPI
ApacheprovidesageneralAPIforcreatingandmaintaininglookup
tables.Apachetablesareubiquitous,usedforeverythingfromstoringthe
currentrequest'soutgoingHTTPheaderstomaintainingthelistof
environmentvariablespassedtosubprocesses.
TablesaresimilartoPerlhashesinthattheyarelistsofkey/valuepairs.
However,unlikeaPerlhash,keysarecase-insensitive,andasinglekey
maycorrespondtoalistofseveralvalues.[2]Inaddition,Apachetable
keysandvaluesarealwaysstrings;arbitrarydatatypescannotbeused.
[2]DespitethedifferencesbetweenPerlhashesandApachetables,

thePerlAPIallowsprogrammerstoaccesstablesviatiedPerl
hashes.SeeSection9.2.5.
10.5.1Thetableandtable_entryDataTypes
Currently,atableisanApachearraycontainingarrayelementsofthe
table_entrydatatype(definedininclude/alloc.h):
typedefstruct{
char*key;/*thekey*/
char*val;/*thevalue*/
}table_entry;
Whenfetchingorsettingthevalueofakey,Apachesearchesforthekey

usingasimplelinearsearch.Sincemosttablesareshort,thisusually
doesn'timposeasignificantoverhead.Youwillusuallynotwantto
accessthetable_entrydirectly,butuseAPIfunctioncallsto
manipulatethekeysandvaluesforyou.Ifyoudoreaddirectlyfromthe
table_entry,anoteintheincludefileindicatesthatyoushouldcheck
thekeyfornull.Thisisbecausethetable_entrymaybemadepartof
amoresophisticatedhashtableinthefuture.
Thetablestructureitselfisaprivatedatatypeintendedtobeaccessed
viaanopaquetable*.Ifyouwanttopeekatitsdefinition,youcanfind


itininclude/alloc.c.Itisequallystraightforward:
structtable{
array_headera;
#ifdefMAKE_TABLE_PROFILE
void*creator;
#endif
};
TheMAKE_TABLE_PROFILEdefineispartofApache'sdebuggingcode
andisusuallyundefined,sotableisreallyjustanarrayheader.
10.5.2CreatingandCopyingTables
Ifyouneedatableofkey/valuepairsthatisprivatetoyourownmodule,
youcanusetheseAPIroutinestocreateit.Youcaneithercreateanew
emptytableorstartwithonethatisalreadydefinedandmakeacopyof
it.Thesefunctionsaredefinedintheinclude/alloc.hfile,whichis
automaticallyincludedwhenyoubringininclude/httpd.h.
table*ap_make_table(pool*p,intnelts)
ap_make_table()createsanewemptytable,givenaresourcepool
pointerandanestimateofthenumberofelementsyouexpectto
add.Iftheneltsargumentisnonzero,thatnumberoftable_entry
tableswillbepre-allocatedforefficiency.Regardlessofitsinitialsize,
thetablegrowsasnecessarytoaccommodatenewentriesandtable
mergingoperations.
Accessitable*my_table=ap_make_table(p,25);
table*ap_copy_table(pool*p,consttable*t)
Thisfunctiontakesaresourcepoolandanexistingtableandmakes
areplicaofthetable,returningapointertothecopy.Youcanthen
changethecontentsofthecopywithoutmodifyingtheoriginal.In
thisexample,wemakeacopyoftheheaders_intable:
table*my_headers=ap_copy_table(r->pool,r->headers_in);


10.5.3GettingandSettingTableValues
Theseroutinesallowyoutoaddnewentriestothetable,tochange
existingones,andtoretrieveentries.
constchar*ap_table_get(consttable*t,constchar*key)
Givenatablepointerandakey,ap_table_get()returnsthevalueof
theentryatthatkeyasachar*.Iftherearemultiplevaluesforthat
particularkey,thefunctionwillonlyreturnthefirstoneitfinds,which
willbethefirstentryadded.
Inthisexample,werecoverthestringvalueoftheincomingUseragentheader:
constchar*ua=ap_table_get(r->headers_in,"User-agent");
Toiteratethroughthemultiplevaluesforthesamekey,usethe
ap_table_do()functiondescribedlaterinthissection.
voidap_table_set(table*t,constchar*key,constchar*val)
ap_table_set()setstheentrynamedbykeytothecharacterstringin
val.Ifanentrywiththesamekeyalreadyexists,itsvalueis
replaced.Otherwise,anewentryiscreated.Ifmorethanoneentry
hasthesamekey,theextraneousonesaredeleted,makingthekey
single-valued.
Internally,Apachecallsap_pstrdup()onthekeyandthevalueand
storescopiesoftheminthetable.Thismeansthatyouareableto
changeordisposeoftheoriginalvariableswithoutworryingabout
disruptingthetable.
Here'sanexampleofusingthisfunctiontosettheoutgoingheaders
fieldLocationtothestringhttp://www.modperl.com/.Because
Locationisasingle-valuedfield,ap_table_set()isthecorrectcallto
use:

ap_table_set(r->headers_out,"Location","http://www.modperl


voidap_table_setn(table*t,constchar*key,constchar*val)
Thisfunctionbehavesthesameasap_table_set(),butthecharacter
stringsforkeyandvalarenotcopiedwithap_pstrdup().Youmust
ensurethatthestringsremainvalidforthelifetimeofthetable.The
previousexampleisagoodcandidateforap_table_setn(),asituses
staticstringsforboththekeyandvalue.
voidap_table_add(table*t,constchar*key,constchar*val)
Thisfunctionissimilartoap_table_set(),butexistingentrieswiththe
samekeyarenotreplaced.Instead,thenewentryisaddedtothe
endofthelist,makingthekeymultivalued.
Internally,Apachecallsap_pstrdup()onthekeyandthevalue,
allowingyoutochangeordisposeoftheoriginalvariableswithout
worryingaboutdisruptingthetable.
ThisexampleaddsseveralSet-cookiefieldstotheoutgoingHTTP
headerstable:
for(i=0;cookies[i];i++){
ap_table_add(r->headers_out,"Set-cookie",cookies[i]);
}
voidap_table_addn(table*t,constchar*key,constchar*val)
Thisfunctionbehaveslikeap_table_add(),butkeyandvalarenot
duplicatedbeforestoringthemintothetable.Thisfunctionsavesa
littletimeandmemoryifyouareworkingwithstaticstrings.
voidap_table_merge(table*t,constchar*key,constchar*val)
ap_table_merge()mergesanewkeyvalueintotheexistingentryby
appendingittowhat'salreadythere.ThisisusedforcommadelimitedheaderfieldssuchasContent-language.Forexample,this
seriesofcallswillresultinavalueofen,fr,spintheContentlanguagefield:
ap_table_merge(r->headers_out,"Content-language","en");


ap_table_merge(r->headers_out,"Content-language","fr");
ap_table_merge(r->headers_out,"Content-language","sp");
Likeap_table_set(),thekeyandvaluearecopiedusingap_pstrdup()
beforemovingthemintothetable.
voidap_table_mergen(table*t,constchar*key,constchar*val)
Thisfunctionisthesameasap_table_merge,butthekeyandval
argumentsarenotcopiedwithap_pstrdup()beforeenteringthem
intothetable.
voidap_table_unset(table*t,constchar*key)
ap_table_unset()deletesallentrieshavingtheindicatedkey.This
exampleremovestheRefererfieldfromtheincomingheaders,
possiblyinpreparationformakingananonymousproxyrequest(see
Chapter7):
ap_table_unset(r->headers_in,"Referer");
voidap_table_do(int(*comp)(void*,constchar*,constchar*),void
*rec,consttable*t,...);
ap_table_get()andap_table_getn()workwellforsingle-valuedkeys,
butthereareafewinstancesinwhichkeysarenotunique.To
accessallthevaluesofthesekeys,youwillhavetouse
ap_table_do()toiterateoverthetable.
Asitsprototypeindicates,thisfunctionismorecomplicatedthanthe
oneswe'veseenbefore.Thefunction'sfirstargumentisapointerto
acallbackfunctionthatwillbecalledduringtheiterationprocess.
Thesecondargumentisavoid*thatcanbeusedtopasssome
arbitraryinformationtothecallback.Thethirdargumentisthetable
*itself.Thisisfollowedbyavariablenumberofchar*key
arguments,terminatedbyanull.ap_table_do()williterateoverthe
table,invokingthecallbackroutineonlywhenatableentries'key
matchesakeyinthegivenlist.Ifnokeysaregiven,thefunctionwill
invokethecallbackroutineforallofthetableentries.


Thecallbackfunctionshouldhavethisfunctionprototype:

intcallback(void*rec,constchar*key,constchar*value);
Thefirstargumentcorrespondstothevoid*argumentpassedto
ap_table_do(),andthesecondandthirdargumentsarethekeyand
valueofthecurrenttableentry.Thecallbackshoulddowhatever
workitneedstodo(forexample,copyingthevalueintoanApache
array),andreturnatruevalue.Thecallbackcanreturninorderto
abortap_table_do()prematurely.
Here'sacallbackthatsimplyprintsoutthekeynameandvalue
withoutperformingfurtherprocessing:

staticintheader_trace(void*data,constchar*key,constc
{
request_rec*r=(request_rec*)data;
ap_rprintf(r,"HeaderField`%s'==`%s'\n",key,val);
returnTRUE;
}
Here'showthecallbackcanbeusedtoprintoutthecontentsofthe
outgoingheaderstable:
ap_table_do(header_trace,r,r->headers_out,NULL);
Andinthisexample,thecallbackisonlyinvokedfortheContent-type
andContent-lengthfields:
ap_table_do(header_trace,(void*)r,r->headers_out,
"Content-type","Content-length",NULL);
10.5.4OtherTableFunctions
Hereareafewmiscellaneoustablefunctionsthatdon'tfitintothe
previouscategories:
table*ap_overlay_tables(pool*p,consttable*overlay,consttable*base)


Thisfunctiontakesthecontentsofthetableatoverlayandaddsit
tothetableatbase.Entriesinoverlaythatdon'texistinbaseare
addedtobase.Entriesthatalreadyexistinbaseareoverwritten.You
canuseap_overlay_tables()toperformabulkupdateofatable.This
exampleoverlaysthefieldslistedinmy_headersontothetableof
outgoingheaders:

table*new_table=_ap_overlay_tables(r->pool,my_headers,r
array_header*ap_table_elts(table*t)
Ifyouwishtoaccessthecontentsofthetabledirectly,youcancall
theap_table_elts()function(it'sapreprocessormacro,actually).It
willreturnanarray_header*,whichyoucantheniteratethrough,
castingeachelementtoatable_entry.
array_header*arr=ap_table_elts(my_table);
intap_is_empty_table(table*t)
Thisfunction(it'sapreprocessormacro,actually)returnstrueifthere
arenoentriesinthegiventable,orfalseotherwise.
if(!ap_is_empty_table(my_table)){
/*thistablehasoneormoreelements*/
}
voidap_clear_table(table*t)
Theap_clear_table()functionclearsallentriesfromthetable.
Example:
ap_clear_table(my_table);


9.2OtherCorePerlAPIClasses
ThevastbulkofthefunctionalityofthePerlAPIiscontainedinthe
Apacheobject.However,anumberofauxiliaryclasses,including
Apache::Table,Apache::Connection,andApache::Server,provide
additionalmethodsforaccessingandmanipulatingthestateofthe
server.Thissectiondiscussestheseclasses.
9.2.1TheApacheTIEHANDLEInterface
IntheCGIenvironment,thestandardinputandstandardoutputfile
descriptorsareredirectedsothatdatareadandwrittenispassedthrough
Apacheforprocessing.IntheApachemoduleAPI,handlersordinarily
usetheApacheread()andprint()methodstocommunicatewiththe
client.However,asaconvenience,mod_perltiestheSTDINand
STDOUTfilehandlestotheApacheclasspriortoinvokingPerlAPI
modules.Thisallowshandlerstoreadfromstandardinputandwriteto
standardoutputexactlyasiftheywereintheCGIenvironment.
TheApacheclasssupportsthefullTIEHANDLEinterface,asdescribed
inperltie(1).STDINandSTDOUTarealreadytiedtoApachebythetime
yourhandleriscalled.Ifyouwishtotieyourowninputoroutput
filehandle,youmaydosobycallingtie()withtherequestobjectasthe
function'sthirdparameter:
tie*BROWSER,'Apache',$r;
printBROWSER'Comeout,comeout,whereveryouare!';
Ofcourse,itisbetternottohardcodetheApacheclassname,as$r
mightbeblessedintoasubclass:
tie*BROWSER,ref$r,$r;
9.2.2TheApache::SubRequestClass
TheApachemethodslookup_uri()andlookup_file()returnarequest
recordobjectblessedintotheApache::SubRequestclass.The


Apache::SubRequestclassisasubclassofApacheandinheritsmostof
itsmethodsfromthere.Herearetwoexamplesoffetchingsubrequest
objects:
my$subr=$r->lookup_file($filename);
my$subr=$r->lookup_uri($uri);
TheApache::SubRequestclassaddsasinglenewmethod,run().
run()
Whenasubrequestiscreated,theURItranslation,accesschecks,
andMIMEcheckingphasesarerun,butunlikearealrequest,the
contenthandlerfortheresponsephaseisnotactuallyrun.Ifyou
wouldliketoinvokethecontenthandler,therun()methodwilldoit:
my$status=$subr->run;
Whenyouinvokethesubrequest'sresponsehandlerinthisway,it
willdoeverythingaresponsehandlerissupposedto,including
sendingtheHTTPheadersandthedocumentbody.run()returns
thecontenthandler'sstatuscodeasitsfunctionresult.Ifyouare
invokingthesubrequestrun()methodfromwithinyourowncontent
handler,youmustnotsendtheHTTPheaderanddocumentbody
yourself,asthiswouldbeappendedtothebottomoftheinformation
thathasalreadybeensent.Mosthandlersthatinvokerun()will
immediatelyreturnitsstatuscode,pretendingtoApachethatthey
handledtherequestthemselves:
my$status=$subr->run;
return$status;
9.2.3TheApache::ServerClass
TheApache::ServerclassprovidesthePerlinterfacetotheCAPI
server_recdatastructure,whichcontainslotsoflow-levelinformation
abouttheserverconfiguration.Withinahandler,thecurrent
Apache::ServerobjectcanbeobtainedbycallingtheApacherequest
object'sserver()method.AtPerlstartuptime(suchaswithinastartup


scriptoramoduleloadedwithPerlModule),youcanfetchtheserver
objectbyinvokingApache->serverdirectly.Byconvention,weusethe
variable$sforserverobjects.
#atrequesttime
subhandler{
my$r=shift;
my$s=$r->server;
....
}
#atserverstartuptime,e.g.,PerlModuleorPerlRequire
my$s=Apache->server;
Thissectiondiscussesthevariousmethodsthatareavailabletoyouvia
theserverobject.Theycorrespondcloselytothefieldsofthe
server_recstructure,whichwerevisitinChapter10.
is_virtual()
Thismethodreturnstrueifthecurrentrequestisbeingappliedtoa
virtualserver.Thisisaread-onlymethod.
my$is_virtual=$s->is_virtual;
log()
Thelog()methodretrievesanobjectblessedintotheApache::Log
class.Youcanthenusethisobjecttoaccessthefull-featured
loggingAPI.SeeSection9.1.6.2"fordetails.
useApache::Log();
my$log=$s->log;
TheApache::Server::log()methodisidenticalinmostrespectstothe
Apache::log()methoddiscussedearlier.Thedifferenceisthat
messagesloggedwithApache::log()willincludetheIPaddressof
thebrowserandaddthemessagestothenotestableunderakey
namederror-notes.Seethedescriptionofnotes()underSection


9.1.4."
port()
Thismethodreturnstheportonwhichthis(virtual)serverislistening.
Ifnoportisexplicitlylistedintheserverconfigurationfile(thatis,the
serverislisteningonthedefaultport80),thismethodwillreturn0.
Usethehigher-levelApache::get_server_port()methodifyouwishto
avoidthispitfall.
my$port=$r->server->port||80;
Thismethodisread-only.
server_admin()
Thismethodreturnstheemailaddressofthepersonresponsiblefor
thisserverasconfiguredbytheServerAdmindirective.
my$admin=$s->server_admin;
Thismethodisread-only.
server_hostname()
Thismethodreturnsthe(virtual)hostnameusedbythisserver,as
setbytheServerNamedirective.
my$hostname=$s->server_hostname;
Thismethodisread-only.
names()
Ifthisserverisconfiguredtousevirtualhosts,thenames()method
willreturnthenamesbywhichthecurrentvirtualhostisrecognized
asspecifiedbytheServerAliasdirectives(includingwildcarded
names).Thefunctionresultisanarrayreferencecontainingthe
hostnames.Ifnoaliasnamesarepresentortheserverisnotusing
virtualhosts,thiswillreturnareferencetoanemptylist.


my$s=$r->server;
my$names=$s->names;
print"Names=@$names\n";
next()
Apachemaintainsalinkedlistofallconfiguredvirtualservers,which
canbeaccessedwiththenext()method.

for(my$s=Apache->server;$s;$s=$s->next){
printf"Contact%sregardingproblemswiththe%ssite\n
$s->server_admin,$s->server_hostname;
}
log_error()
ThismethodisthesameastheApache::log_error()method,except
thatit'savailablethroughtheApache::Serverobject.Thisallowsyou
touseitinPerlstartupfilesandotherplaceswheretherequest
objectisn'tavailable.
my$s=Apache->server;
$s->log_error("Can'topenconfigfile$!");
warn()
ThismethodisthesameastheApache::warn()method,butit's
availablethroughtheApache::Serverobject.Thisallowsyoutouse
itinPerlstartupfilesandotherplaceswheretherequestobjectisn't
available.
my$s=Apache->server;
$s->warn("Can'tpreloadscript$file$!");
9.2.4TheApache::ConnectionClass
TheApache::ConnectionclassprovidesaPerlinterfacetotheClanguageconn_recdatastructure,whichprovidesvariouslow-level
detailsaboutthenetworkconnectionbacktotheclient.Withinahandler,


theconnectionobjectcanbeobtainedbycallingtheApacherequest
object'sconnection()method.Theconnectionobjectisnotavailable
outsideofhandlersforthevariousrequestphasesbecausethereisno
connectionestablishedinthosecases.Byconvention,weusethe
variable$cforconnectionobjects.
subhandler{
my$r=shift;
my$c=$r->connection;
...
}
Inthissectionwediscussthevariousmethodsmadeavailablebythe
connectionobject.TheycorrespondcloselytothefieldsoftheCAPI
conn_recstructurediscussedinChapter10.
aborted()
Thismethodreturnstrueiftheclienthasbrokentheconnection
prematurely.Thiscanhappeniftheremoteuser'scomputerhas
crashed,anetworkerrorhasoccurred,or,moretrivially,theuser
pressedthestopbuttonbeforetherequestorresponsewasfully
transmitted.However,thisvalueisonlysetifasofttimeoutoccurred.
if($c->aborted){
warn"uh,oh,theclienthasgoneaway!";
}
Seethedescriptionofsoft_timeout()earlier.
auth_type()
Ifauthenticationwasusedtoaccessapasswordprotected
document,thismethodreturnsthetypeofauthenticationthatwas
used,currentlyeitherBasicorDigest.Thismethodisdifferentfrom
therequestobject'sauth_type()method,whichwediscussed
earlier,becausetherequestobject'smethodreturnsthevalueofthe
AuthTypeconfigurationdirective;inotherwords,thetypeof
authenticationtheserverwouldliketouse.Theconnectionobject's


auth_type()methodreturnsavalueonlywhenauthenticationwas
successfullycompletedandreturnsundefotherwise.
if($c->auth_typene'Basic'){
warn"phew,Ifeelabitbetter";
}
Thismethodisread-only.
local_addr()
ThismethodreturnsapackedSOCKADDR_INstructureinthesame
formatasreturnedbythePerlSocketmodule'spack_sockaddr_in()
function.ThispackedstructurecontainstheportandIPaddressat
theserver'ssideoftheconnection.Thisissetbytheserverwhen
theconnectionrecordiscreated,soitisalwaysdefined.
useSocket();
subhandler{
my$r=shift;
my$local_add=$r->connection->local_addr;
my($port,$ip)=Socket::unpack_sockaddr_in($local_add);
...
}
Forobviousreasons,thismethodisread-only.
remote_addr()
ThismethodreturnsapackedSOCKADDR_INstructurefortheport
andIPaddressattheclient'ssideoftheconnection.Thisissetby
theserverwhentheconnectionrecordiscreated,soitisalways
defined.
Amongotherthings,theinformationreturnedbythismethodand
local_addr()canbeusedtoperformRFC1413identlookupsonthe
remoteclient,evenwhentheconfigurationdirectiveIdentityCheckis
turnedoff.HereisanexampleusingJan-PieterCornet'sNet::Ident
module:


useNet::Identqw(lookupFromInAddr);
my$remoteuser=lookupFromInAddr($c->local_addr,
$c->remote_addr,2);
remote_host()
Thismethodreturnsthehostnameoftheremoteclient.Itonly
returnsthenameiftheHostNameLookupsdirectiveissettoOnand
theDNSlookupwassuccessfulthatis,theDNScontainsareverse
nameentryfortheremotehost.Ifhostname-basedaccesscontrolis
inuseforthegivenrequest,adouble-reverselookupwilloccur
regardlessoftheHostNameLookupssetting,inwhichcase,the
cachedhostnamewillbereturned.Ifunsuccessful,themethod
returnsundef.
Itisalmostalwaysbettertousethehigh-levelget_remote_host()
methodavailablefromtheApacherequestobject(discussedearlier).
Thehigh-levelmethodreturnsthedottedIPaddressoftheremote
hostifitsDNSnameisn'tavailable,anditcachestheresultsof
previouslookups,avoidingoverheadwhenyoucallthemethod
multipletimes.

my$remote_host=$c->remote_host||"nohost";
my$remote_host=$r->get_remote_host(REMOTE_HOST);#better
Thismethodisread-only.
remote_ip()
Thismethodreturnsthedotteddecimalrepresentationoftheremote
client'sIPaddress.Itissetbytheserverwhentheconnectionrecord
iscreatedandisalwaysdefined.
my$remote_ip=$c->remote_ip;
Theremote_ip()canalsobechanged,whichishelpfulifyourserver
isbehindaproxysuchasthesquidaccelerator.ByusingtheXForwarded-Forheadersentbytheproxy,theremote_ipcanbesetto
thisvaluesologgingmodulesincludetheaddressoftherealclient.


TheonlysubtlepointisthatX-Forwarded-Formaybemultivaluedin
thecaseofasinglerequestthathasbeenforwardedacrossmultiple
proxies.It'ssafesttochoosethelastIPaddressinthelistsincethis
correspondstotheoriginalclient.
my$header=$r->headers_in->{'X-Forwarded-For'};
if(my$ip=(split/,\s*/,$header)[-1]){
$r->connection->remote_ip($ip);
}
remote_logname()
Thismethodreturnstheloginnameoftheremoteuser,providedthat
theconfigurationdirectiveIdentityCheckissettoOnandtheremote
user'smachineisrunninganidentddaemon.Ifoneorbothofthese
conditionsisfalse,themethodreturnsundef.
Itisbettertousethehigh-levelget_remote_logname()methodwhich
isprovidedbytherequestobject.Whenthehigh-levelmethodis
called,theresultiscachedandreusedifcalledagain.Thisisnot
trueofremote_logname().
my$remote_logname=$c->remote_logname||"nobody";
my$remote_logname=$r->get_remote_logname;#better
user()
WhenBasicauthenticationisineffect,user()returnsthenamethat
theremoteuserprovidedwhenpromptedforhisusernameand
password.Thepassworditselfcanberecoveredfromtherequest
objectbycallingget_basic_auth_pw().
my$username=$c->user;
9.2.5TheApache::TableClass
TheHTTPmessageprotocolissimplelargelybecauseofitsconsistent
useofthekey/valueparadigminitsrequestandresponseheaderfields.
Becausemuchofanexternalmodule'sworkisgettingandsettingthese


headerfields,Apacheprovidesasimpleyetpowerfulinterfacecalledthe
tablestructure.Apachetablesarekeyedcase-insensitivelookup
tables.APIfunctioncallsallowyoutoobtainthelistofdefinedkeys,
iteratethroughthem,getthevalueofakey,andsetkeyvalues.Since
manyHTTPheaderfieldsarepotentiallymultivalued,Apachealso
providesfunctionalityforgetting,setting,andmergingthecontentsof
multivaluedfields.
ThefollowingfiveCdatastructuresareimplementedastables.Thislist
islikelytogrowinthefuture.
headers_in
headers_out
err_headers_out
notes
subprocess_env
AsdiscussedinSection9.1,"thePerlAPIprovidesfivemethodcalls,
namedheaders_in(),headers_out(),err_headers_out(),notes(),and
subprocess_env(),thatretrievethesetables.ThePerlmanifestationof
theApachetableAPIistheApache::Tableclass.ItprovidesaTIEHASH
interfacethatallowstransparentaccesstoitsmethodsviaatiedhash
reference,aswellasAPImethodsthatcanbecalleddirectly.
TheTIEHASHinterfaceiseasytouse.Simplycalloneofthemethods
listedearlierinascalarcontexttoreturnatiedhashreference.For
example:
my$table=$r->headers_in;
Thereturnedobjectcannowbeusedtogetandsetvaluesinthe
headers_intablebytreatingitasanordinaryhashreference,butthe
keysarelookedupcase-insensitively.Examples:
my$type=$table->{'Content-type'};


my$type=$table->{'CONTENT-TYPE'};#samething
$table->{'Expires'}='Sat,08Aug199801:39:20GMT';
Ifthefieldyouaretryingtoaccessismultivalued,thenthetiedhash
interfacesuffersthelimitationthatfetchingthekeywillonlyreturnthefirst
definedvalueofthefield.Youcangetaroundthisbyusingtheobjectorientedinterfacetoaccessthetable(weshowanexampleofthislater)
orbyusingtheeachoperatortoaccesseachkeyandvaluesequentially.
ThefollowingcodesnippetshowsonewaytofetchalltheSet-cookie
fieldsintheoutgoingHTTPheader:
while(my($key,$value)=each%{$r->headers_out}){
push@cookies,$valueiflc($key)eq'set-cookie';
}
WhenyoutreatanApache::Tableobjectasahashreference,youare
accessingitsinternalget()andset()methods(amongothers)indirectly.
TogainaccesstothefullpowerofthetableAPI,youcaninvokethese
methodsdirectlybyusingthemethodcallsyntax.
HereisthelistofpubliclyavailablemethodsinApache::Table,alongwith
briefexamplesofusage:
add()
Theadd()methodwilladdakey/valuepairtothetable.Because
Apachetablescancontainmultipleinstancesofakey,youmaycall
add()multipletimeswithdifferentvaluesforthesamekey.Instead
ofthenewvalueofthekeyreplacingthepreviousone,itwillsimply
beappendedtothelist.ThisisusefulformultivaluedHTTPheader
fieldssuchasSet-Cookie.TheoutgoingHTTPheaderwillcontain
multipleinstancesofthefield.
my$out=$r->headers_out;
formy$cookie(@cookies){
$out->add("Set-cookie"=>$cookie);
}
Anotherwaytoaddmultiplevaluesistopassanarrayreferenceas
thesecondargument.Thiscodehasthesameeffectastheprevious


example:
my$out=$r->headers_out;
$out->add("Set-cookie"=>\@cookies);
clear()
Thismethodwipesthecurrenttableclean,discardingitscurrent
contents.It'sunlikelythatyouwouldwanttoperformthisonapublic
table,buthere'sanexamplethatclearsthenotestable:
$r->notes->clear;
do()
Thismethodprovidesawaytoiteratethroughanentiretableitemby
item.Passitareferencetoacodesubroutinetobecalledoncefor
eachtableentry.Thesubroutineshouldaccepttwoarguments
correspondingtothekeyandvalue,respectively,andshouldreturna
truevalue.Theroutinecanreturnafalsevaluetoterminatethe
iterationprematurely.
Thisexampledumpsthecontentsoftheheaders_infieldtothe
browser:
$r->headers_in->do(sub{
my($key,$value)=@_;
$r->print("$key=>$value\n");
1;
});
Foranotherexampleofdo(),seeChapter7,whereweuseitto
transfertheincomingheadersfromtheincomingApacherequestto
anoutgoingLWPHTTP::Requestobject.
get()
Probablythemostfrequentlycalledmethod,theget()function
returnsthetablevalueatthegivenkey.Formultivaluedkeys,get()
implementsalittlesyntacticsugar.Calledinascalarcontext,it


returnsthefirstvalueinthelist.Calledinanarraycontext,itreturns
allvaluesofthemultivaluedkey.
my$ua=$r->headers_in->get('User-agent');
my@cookies=$r->headers_in->get('Cookie');
get()istheunderlyingmethodthatiscalledwhenyouusethetied
hashinterfacetoretrieveakey.However,theabilitytofetcha
multivaluedkeyasanarrayisonlyavailablewhenyoucallget()
directlyusingtheobject-orientedinterface.
merge()
merge()behaveslikeadd(),exceptthateachtimeitiscalledthe
newvalueismergedintothepreviousone,creatingasingleHTTP
headerfieldcontainingmultiplecomma-delimitedvalues.
IntheHTTPprotocol,acomma-separatedlistofheadervaluesis
equivalenttothesamevaluesspecifiedbyrepeatedheaderlines.
Somebuggyclientsmaynotacceptmergedheaders,however.In
thiscase,itisworthwhiletocontrolthemergingexplicitlyandavoid
mergingheadersthatcausetrouble(likeSet-cookie).
merge()workslikeadd().Youcaneithermergeaseriesofentries
oneatatime:
my@languages=qw(enfrde);
foreach(@languages){
$r->headers_out->merge("Content-language"=>$_);
}
ormergeabunchofentriesinasinglestepbypassinganarray
reference:
$r->headers_out->merge("Content-language"=>\@languages);
new()
Thenew()methodisavailabletocreateanApache::Tableobject
fromscratch.ItrequiresanApacheobjecttoallocatethetableand,


optionally,thenumberofentriestoinitiallyallocate.Notethatjustlike
theotherApache::TableobjectsreturnedbyAPImethods,
referencescannotbeusedasvalues,onlystrings.

my$tab=Apache::Table->new($r);#default,allocates10ent
my$tab=Apache::Table->new($r,20);#allocate20entries
set()
set()takesakey/valuepairandupdatesthetablewithit,creating
thekeyifitdidn'texistbefore,orreplacingitspreviousvalue(s)ifit
did.Theresultingheaderfieldwillbesingle-valued.Internallythis
methodiscalledwhenyouassignavaluetoakeyusingthetied
hashinterface.
Here'sanexampleofusingset()toimplementanHTTPredirect:

$r->headers_out->set(Location=>'http://www.modperl.com/');
unset()
Thismethodcanbeusedtoremoveakeyanditscontents.Ifthere
aremultipleentrieswiththesamekey,theywillallberemoved.
$r->headers_in->unset('Referer');
9.2.6TheApache::URIClass
ApacheVersion1.3introducedautilitymoduleforparsingURIs,
manipulatingtheircontents,andunparsingthembackintostringform.
SincethisfunctionalityispartoftheserverCAPI,Apache::URIoffersa
lightweightalternativetotheURI::URLmodulethatshipswiththe
libwww-perlpackage.[5]
[5]Atthetimeofthiswriting,URI::URLwasscheduledtobe

replacedbyURI.pm,whichwillbedistributedseparatelyfromthe
libwww-perlpackage.


AnApache::URIobjectisreturnedwhenyoucalltherequestobject's
parsed_uri()method.YoumayalsocalltheApache::URIparse()
constructortoparseanarbitrarystringandreturnanewApache::URI
object,forexample:
useApache::URI();
my$parsed_uri=$r->parsed_uri;
fragment()
ThismethodreturnsorsetsthefragmentcomponentoftheURI.You
knowthisasthepartthatfollowsthehashmark(#)inlinks.The
fragmentcomponentisgenerallyusedonlybyclientsandsomeweb
proxies.
my$fragment=$uri->fragment;
$uri->fragment('section_1');
hostinfo()
Thismethodgetsorsetstheremotehostinformation,whichusually
consistsofahostnameandportnumberintheformat
hostname:port.SomerareURIs,suchasthoseusedfor
nonanonymousFTP,attachausernameandpasswordtothis
information,foruseinaccessingprivateresources.Inthiscase,the
informationreturnedisintheformat
username:password@hostname:port.
Thismethodreturnsthehostinformationwhencalledwithout
arguments,orsetstheinformationwhencalledwithasinglestring
argument.
my$hostinfo=$uri->hostinfo;
$uri->hostinfo('www.modperl.com:8000');
hostname()
ThismethodreturnsorsetsthehostnamecomponentoftheURI
object.


my$hostname=$uri->hostname;
$uri->hostname('www.modperl.com');
parse()
Theparse()methodisaconstructorusedtocreateanew
Apache::URIobjectfromaURIstring.ItsfirstargumentisanApache
requestobject,andthesecondisastringcontaininganabsoluteor
relativeURI.InthecaseofarelativeURI,theparse()methoduses
therequestobjecttodeterminethelocationofthecurrentrequest
andresolvetherelativeURI.

my$uri=Apache::URI->parse($r,'http://www.modperl.com/');
IftheURIargumentisomitted,theparse()methodwillconstructa
fullyqualifiedURIfrom$r,includingthescheme,hostname,port,
path,andquerystring.
my$self_uri=Apache::URI->parse($r);
password()
Thismethodgetsorsetsthepasswordpartofthehostinfo
component.
my$password=$uri->password;
$uri->password('rubble');
path()
ThismethodreturnsorsetsthepathcomponentoftheURIobject.
my$path=$uri->path;
$uri->path('/perl/hangman.pl');
path_info()
Afterthe"realpath"partoftheURIcomesthe"additionalpath
information."ThiscomponentoftheURIisnotdefinedbytheofficial
URIRFC,becauseitisaninternalconceptfromwebserversthat


needtodosomethingwiththepartofthepathinformationthatisleft
overfromtranslatingthepathintoavalidfilename.
path_info()getsorsetstheadditionalpathinformationportionofthe
URI,usingthecurrentrequestobjecttodeterminewhatpartofthe
pathisrealandwhatpartisadditional.
$uri->path_info('/foo/bar');
port()
ThismethodreturnsorsetstheportcomponentoftheURIobject.
my$port=$uri->port;
$uri->port(80);
query()
ThismethodgetsorsetsthequerystringcomponentoftheURI;in
otherwords,thepartafterthe?.
my$query=$uri->query;
$uri->query('one+two+three');
rpath()
Thismethodreturnsthe"realpath;"thatis,thepath()minusthe
path_info().
my$path=$uri->rpath();
scheme()
ThismethodreturnsorsetstheschemecomponentoftheURI.This
isthepartthatidentifiestheURI'sprotocol,suchashttporftp.
Calledwithoutarguments,thecurrentschemeisretrieved.Called
withasinglestringargument,thecurrentschemeisset.
my$scheme=$uri->scheme;
$uri->scheme('http');


unparse()
ThismethodreturnsthestringrepresentationoftheURI.Relative
URIsareresolvedintoabsoluteones.
my$string=$uri->unparse;
Bewarethattheunparse()methoddoesnottaketheadditionalpath
informationintoaccount.ItreturnstheURIminustheadditional
information.
user()
Thismethodgetsorsetstheusernamepartofthehostinfo
component.
my$user=$uri->user;
$uri->user('barney');
9.2.7TheApache::UtilClass
TheApacheAPIprovidesseveralutilityfunctionsthatareusedby
variousstandardmodules.ThePerlAPImakestheseavailableas
functioncallsintheApache::Utilpackage.
Althoughthereisnothingherethatdoesn'talreadyexistinsomeexisting
Perlmodule,theseCversionsareconsiderablyfasterthantheir
correspondingPerlfunctionsandavoidthememorybloatofpullinginyet
anotherPerlpackage.
Tomakethesefunctionsavailabletoyourhandlers,importthe
Apache::Utilmodulewithanimporttagof:all:
useApache::Utilqw(:all);
escape_uri()
ThisfunctionencodesallunsafecharactersinaURIinto%XXhex
escapesequences.Thisisequivalenttothe
URI::Escape::uri_escape()functionfromtheLWPpackage.


Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay

×

×