Ahookfunctioncanbeunderstoodasahook,anditsfunctionistohangsomethingupwhennecessary.Thespecificexplanationis:thehookfunctionistohookourownimplementedhookfunctiontothetargetmountpointatacertainmoment.
Ibelieveyouarefamiliarwithhookfunctions.I’veseensimilardesignsinrequestsandmitmproxy.
Forexample,statuscodeneedstobeprintedinrequests:
#requests_hooks.py importrequests r=requests.get("https://httpbin.org/get") print(f"statusdoce:{r.status_code}")
Printingthestatuscode,thisactioncanbeencapsulatedintoafunctionandthenpassedtorequestsasahookfunction.
#requests_hooks.py importrequests defstatus_code(response,*args,**kwargs): print(f"hookstatusdoce:{response.status_code}") r=requests.get("https://httpbin.org/get",hooks={"response":status_code})
CodeDescription:
Encapsulatetheprintingstatuscodeintoastatus_code()function,andreceivethehookfunctionstatus_code()throughthehooksparameterintherequests.get()method.
Runresults:
>pythonrequests_hooks.py hookstatusdoce:200
status_code()
Asafunction,itcandomanythings,suchasfurtherjudgingthestatuscode,printingtheresponsedata,andevenencryptinganddecryptingthecorrespondingdata.
mitmproxyisaproxytool,whichwehavealsointroducedinourpreviousarticle.Duringthepacketcaptureprocess,youalsoneedtousehookstodosomeadditionalprocessingontherequestorresponse.
#anatomy.py """ Basicskeletonofamitmproxyaddon. Runasfollows:mitmproxy-sanatomy.py """ importlogging classCounter: def__init__(self): self.num=0 defrequest(self,flow): self.num=self.num+1 logging.info("We'veseen%dflows"%self.num) addons=[Counter()]
Runmitmproxy
>mitmproxy-sanatomy.py
Whenitisnecessarytoimplementhooks,itiswhenafunction(class/method)cannotmeetallneedsbyitself,sohookscanbeusedtoprovidethepossibilityofexpandingitsowncapabilities.
Itisnotdifficulttoimplementhooks,lookattheexample:
importtime classProgrammer(object): """programmer""" def__init__(self,name,hook=None): self.name=name self.hooks_func=hook self.now_date=time.strftime("%Y-%m-%d") defget_to_eat(self): print(f"{self.name}-{self.now_date}:eat.") defgo_to_code(self): print(f"{self.name}-{self.now_date}:code.") defgo_to_sleep(self): print(f"{self.name}-{self.now_date}:sleep.") defeveryday(self): #Threethingsthatprogrammersdoeveryday self.get_to_eat() self.go_to_code() self.go_to_sleep() #checktheregister_hook(hookedorunhooked) #hooked ifself.hooks_funcisnotNone: self.hooks_func(self.name) defplay_game(name): now_date=time.strftime("%Y-%m-%d") print(f"{name}-{now_date}:playgame.") defshopping(name): now_date=time.strftime("%Y-%m-%d") print(f"{name}-{now_date}:shopping.") if__name__=="__main__": #hookispassedinasaparameter tom=Programmer("Tom",hook=play_game) jerry=Programmer("Jerry",hook=shopping) spike=Programmer("Spike") #today’sevents tom.everyday() jerry.everyday() spike.everyday()
CodeDescription:
Intheaboveexample,theProgrammerclassimplementsthreefunctions:eat,code,andsleep.However,programmersarealsoordinarypeopleandcannotjusteat,code,andsleepeveryday,soregister_hook()providestheabilitytodootherthings.
So,takealookatwhatthethreeprotagonistsTom,Jerry,andSpikedidtoday!
Runresults:
Tom-2022-12-01:eat. Tom-2022-12-01:code. Tom-2022-12-01:sleep. Tom-2022-12-01:playgame. Jerry-2022-12-01:eat. Jerry-2022-12-01:code. Jerry-2022-12-01:sleep. Jerry-2022-12-01:shopping. Spike-2022-12-01:eat. Spike-2022-12-01:code. Spike-2022-12-01:sleep.
Ifyouunderstandhookas:definingafunctionandtheninsertingitasaparameterintoanotherclass/method.Obviously,thisisjustoneusage.Ithoughtaboutitagain.Thedebugtalk.py
fileofhttpRunner;theconftest.py
fileofpytestarealsohookfileswithspecialnames.Duringtheexecutionoftheprogram,thehookfunctionsinthesefilesarecalledtocompletesomespecialtasks.
Takepytestasanexample
└───project ├───conftest.py └───test_sample.py
- conftest.py
importpytest @pytest.fixture() defbaidu_url(): """Definehookfunction""" return"https://www.baidu.com"
- test_sample.py
importwebbrowser deftest_open_url(baidu_url): #Callbaidu_urlhookfunction #Callthebrowsertoaccessbaidu_url webbrowser.open_new(baidu_url)
Thetwofilesseemtohavenodirectcallingrelationship.Whenexecutingthetest_sample.py
file,youcanindirectlycallbaidu_url()
file./code>Hookfunction.
Executetest
>pytest-qtest_sample.py
Next,let’strytocreateasimilarfunction.
└───project ├───run_conf.py ├───loader.py └───run.py
- run_conf.py
defbaidu_url(): """Definehookfunction""" name="https://www.baidu.com" returnname
Similartotheconftest.py
file,thehookfunctionisimplementedinthisfile.
- loader.py
importos importinspect importimportlib defloader(name): """ Dynamicallyexecutehookfunctions """ #Directoryofthecalledfile stack_t=inspect.stack() ins=inspect.getframeinfo(stack_t[1][0]) file_dir=os.path.dirname(os.path.abspath(ins.filename)) #*_conf.pyfileunderthecalledfiledirectory all_hook_files=list(filter(lambdax:x.endswith("_conf.py"),os.listdir(file_dir))) all_hook_module=list(map(lambdax:x.replace(".py",""),all_hook_files)) #Dynamicallyload*_config.py hooks=[] formodule_nameinall_hook_module: hooks.append(importlib.import_module(module_name)) #Basedonthepassednamefunctionname,searchandexecuteitfromthe*_conf.pyfile. forper_hookinhooks: #Dynamicallyexecuteprocessfunction func=getattr(per_hook,name) returnfun()
Thisthingismorecomplicated.Itsfunctionistothrowitafunctionname.Itcanfindthecorrespondingfunctionnameinthe*_conf.py
fileandreturnthefunctionexecutionresult.
Theloader()
functionisauniversalthing,youcanputitanywhereanduseit.
- run.py
importwebbrowser fromloaderimportloader deftest_open_url(): #Callbaidu_urlhookfunction #Callthebrowsertovisitbaidu_url url=loader("baidu_url") webbrowser.open_new(url) if__name__=='__main__': test_open_url()
Executethebaidu_url
hookfunctionthroughtheloader()
functionandgettheurl.
Notethatwedonotneedtoimportthemodulelikethetraditionalwayfromrun_confimportbaidu_url
,weonlyneedtoknowthenameofthehookfunction.
Theimplementationhereisnotaselegantaspytest,butitisclose.
Finally,Iwouldliketothankeveryonewhoreadmyarticlecarefully.Reciprocityisalwaysnecessary.Althoughitisnotaveryvaluablething,ifyoucanuseit,youcantakeitdirectly:
Thisinformationshouldbethemostcomprehensiveandcompletepreparationwarehousefor[softwaretesting]friends.Thiswarehousehasalsoaccompaniedtensofthousandsoftestengineersthroughthemostdifficultjourney.Ihopeitcanalsohelpyou!
Theknowledgepointsofthearticlematchtheofficialknowledgefiles,andyoucanfurtherlearnrelevantknowledge.PythonentryskilltreeBasicgrammarFunction386776peoplearelearningthesystem