1.golangï¼contextä»ç»
golangï¼contextä»ç»
1 åè¨
æè¿å®ç°ç³»ç»çåå¸å¼æ¥å¿ä¸äºå¡ç®¡çæ¶,源码ssrf漏洞源码å¨å¯»æ±æè°çå ¨å±å¯ä¸Goroutine IDæ æä¹å,å³å®è¿æ¯ç®åå©ç¨Contextæºå¶å®ç°äºåºæ¬çæ³æ³,ä¸å¤é«æ,ä½æ¯å¥½ç¨.äºæ¯å¯¹å®å½åç设计æ¯è¾å¥½å¥,便æäºæ¤æ.
Contextæ¯golangå®æ¹å®ä¹çä¸ä¸ªpackage,å®å®ä¹äºContextç±»å,éé¢å å«äºDeadline/Done/Erræ¹æ³ä»¥åç»å®å°Contextä¸çæååéå¼Value,å ·ä½å®ä¹å¦ä¸ï¼
typeContextinterface{ //è¿åContextçè¶ æ¶æ¶é´ï¼è¶ æ¶è¿ååºæ¯ï¼Deadline()(deadlinetime.Time,okbool)//å¨Contextè¶ æ¶æåæ¶æ¶ï¼å³ç»æäºï¼è¿åä¸ä¸ªå ³éçchannel//å³å¦æå½åContextè¶ æ¶æåæ¶æ¶,Doneæ¹æ³ä¼è¿åä¸ä¸ªchannel,ç¶åå ¶ä»å°æ¹å°±å¯ä»¥éè¿å¤æDoneæ¹æ³æ¯å¦æè¿åï¼channelï¼,å¦ææå说æContextå·²ç»æ//æ å ¶å¯ä»¥ä½ä¸ºå¹¿æéç¥å ¶ä»ç¸å ³æ¹æ¬Contextå·²ç»æ,请åç¸å ³å¤ç.Done()<-chanstruct{ }//è¿åContextåæ¶çåå Err()error//è¿åContextç¸å ³æ°æ®Value(keyinterface{ })interface{ }}é£ä¹å°åºä»ä¹Contextï¼å¯ä»¥åé¢ææå¯ä»¥ç解为ä¸ä¸æ,æ¯è¾çæçæè¿ç¨/线ç¨ä¸çº¿æ,å ³äºgolangä¸çä¸ä¸æ,ä¸å¥è¯æ¦æ¬å°±æ¯ï¼ goroutineçç¸å ³ç¯å¢å¿«ç §,å ¶ä¸å å«å½æ°è°ç¨ä»¥åæ¶åçç¸å ³çåéå¼. éè¿Contextå¯ä»¥åºåä¸åçgoroutine请æ±,å 为å¨golang Seversä¸,æ¯ä¸ªè¯·æ±é½æ¯å¨å个goroutineä¸å®æç.
æè¿å¨å ¬å¸åægRPCæºç ,protoæ件çæç代ç ,æ¥å£å½æ°ç¬¬ä¸ä¸ªåæ°ç»ä¸æ¯ctx context.Contextæ¥å£,å ¬å¸ä¸å°åäºé½ä¸äºè§£è¿æ ·è®¾è®¡çåºåç¹æ¯ä»ä¹,å ¶å®æä¹ä¸äºè§£å ¶èåçåç.ä»å¤©è¶ç妮妲å°é£å¦¹åæ£é¢ç»éæ·±å³,å ¨å¸åå·¥,å课,åä¸,å¨å®¶ä¼æ¯æ¾äºä¸äºèµæç 究æç©ä¸æ.
Contexté常被è¯ä½ä¸ä¸æ,å®æ¯ä¸ä¸ªæ¯è¾æ½è±¡çæ¦å¿µ.å¨å ¬å¸ææ¯è®¨è®ºæ¶ä¹ç»å¸¸ä¼æå°ä¸ä¸æ.ä¸è¬ç解为ç¨åºåå çä¸ä¸ªè¿è¡ç¶æ,ç°åº,å¿«ç §,èç¿»è¯ä¸ä¸ä¸åå¾å¥½å°è¯ éäºå ¶æ¬è´¨,ä¸ä¸ä¸ä¸åæ¯åå¨ä¸ä¸å±çä¼ é,ä¸ä¼æå å®¹ä¼ éç»ä¸.å¨Goè¯è¨ä¸,ç¨åºåå ä¹å°±æçæ¯Goroutine.
æ¯ä¸ªGoroutineå¨æ§è¡ä¹å,é½è¦å ç¥éç¨åºå½åçæ§è¡ç¶æ,é常å°è¿äºæ§è¡ç¶æå°è£ å¨ä¸ä¸ªContextåéä¸,ä¼ éç»è¦æ§è¡çGoroutineä¸. ä¸ä¸æåå ä¹å·²ç»æä¸ºä¼ éä¸è¯·æ±åçåå¨æåéçæ åæ¹æ³.å¨ç½ç»ç¼ç¨ä¸,å½æ¥æ¶å°ä¸ä¸ªç½ç»è¯·æ±Request,å¤çRequestæ¶,æ们å¯è½éè¦å¼å¯ä¸åçGoroutineæ¥è·åæ°æ®ä¸é»è¾å¤ç,å³ä¸ä¸ªè¯·æ±Request,ä¼å¨å¤ä¸ªGoroutineä¸å¤ç. èè¿äºGoroutineå¯è½éè¦å ±äº«Requestçä¸äºä¿¡æ¯;åæ¶å½Request被åæ¶æè è¶ æ¶çæ¶å,ææä»è¿ä¸ªRequestå建çææGoroutineä¹åºè¯¥è¢«ç»æ.
注ï¼å ³äºgoroutineçç解å¯ä»¥ç§»æ¥è¿é.
2 为ä»ä¹ä½¿ç¨contextç±äºå¨golang seversä¸,æ¯ä¸ªrequesté½æ¯å¨å个goroutineä¸å®æ,并ä¸å¨å个goroutineï¼ä¸å¦¨ç§°ä¹ä¸ºAï¼ä¸ä¹ä¼æ请æ±å ¶ä»æå¡ï¼å¯å¨å¦ä¸ä¸ªgoroutineï¼ç§°ä¹ä¸ºBï¼å»å®æï¼çåºæ¯,è¿å°±ä¼æ¶åå¤ä¸ªGoroutineä¹é´çè°ç¨.å¦ææä¸æ¶å»è¯·æ±å ¶ä»æå¡è¢«åæ¶æè è¶ æ¶,åä½ä¸ºæ·±é·å ¶ä¸çå½ågoroutine Béè¦ç«å³éåº,ç¶åç³»ç»æå¯åæ¶Bæå ç¨çèµæº. å³ä¸ä¸ªrequestä¸é常å å«å¤ä¸ªgoroutine,è¿äºgoroutineä¹é´é常ä¼æ交äº.
é£ä¹,å¦ä½ææ管çè¿äºgoroutineæ为ä¸ä¸ªé®é¢ï¼ä¸»è¦æ¯éåºéç¥åå æ°æ®ä¼ éé®é¢ï¼,Googleç解å³æ¹æ³æ¯Contextæºå¶,ç¸äºè°ç¨çgoroutineä¹é´éè¿ä¼ écontextåéä¿æå ³è,è¿æ ·å¨ä¸ç¨æ´é²ågoroutineå é¨å®ç°ç»èçåæä¸,ææå°æ§å¶ågoroutineçè¿è¡.
å¦æ¤ä¸æ¥,éè¿ä¼ éContextå°±å¯ä»¥è¿½è¸ªgoroutineè°ç¨æ ,并å¨è¿äºè°ç¨æ ä¹é´ä¼ ééç¥åå æ°æ®. è½ç¶goroutineä¹é´æ¯å¹³è¡ç,没æ继æ¿å ³ç³»,ä½æ¯Context设计ææ¯å å«ç¶åå ³ç³»ç,è¿æ ·å¯ä»¥æ´å¥½çæè¿°goroutineè°ç¨ä¹é´çæ åå ³ç³».
3 æä¹ä½¿ç¨contextçæä¸ä¸ªContext主è¦æ两类æ¹æ³ï¼
3.1 顶å±Contextï¼Backgroundè¦å建Contextæ ,é¦å å°±æ¯è¦åå»ºæ ¹èç¹
//è¿åä¸ä¸ªç©ºçContext,å®ä½ä¸ºææç±æ¤ç»§æ¿Contextçæ ¹èç¹funcBackground()Context该Contexté常ç±æ¥æ¶requestç第ä¸ä¸ªgoroutineå建,å®ä¸è½è¢«åæ¶,没æå¼,ä¹æ²¡æè¿ææ¶é´,常ä½ä¸ºå¤çrequestç顶å±contextåå¨.
3.2 ä¸å±Contextï¼WithCancel/WithDeadline/WithTimeoutæäºæ ¹èç¹ä¹å,æ¥ä¸æ¥å°±æ¯å建ååèç¹.为äºå¯ä»¥å¾å¥½çæ§å¶ååèç¹,Contextå æä¾çå建æ¹æ³åæ¯å¸¦æ第äºè¿åå¼ï¼CancelFuncç±»åï¼,å®ç¸å½äºä¸ä¸ªHook,å¨ågoroutineæ§è¡è¿ç¨ä¸,å¯ä»¥éè¿è§¦åHookæ¥è¾¾å°æ§å¶ågoroutineçç®çï¼é常æ¯åæ¶,å³è®©å ¶åä¸æ¥ï¼.åé åContextæä¾çDoneæ¹æ³,ågoroutineå¯ä»¥æ£æ¥èªèº«æ¯å¦è¢«ç¶çº§èç¹Cancelï¼
select{ case<-ctx.Done()://dosomecleanâ¦}注ï¼ç¶èç¹Contextå¯ä»¥ä¸»å¨éè¿è°ç¨cancelæ¹æ³åæ¶åèç¹Context,èåèç¹Contextåªè½è¢«å¨çå¾ .åæ¶ç¶èç¹Contextèªèº«ä¸æ¦è¢«åæ¶ï¼å¦å ¶ä¸çº§èç¹Cancelï¼,å ¶ä¸çææåèç¹Contextåä¼èªå¨è¢«åæ¶.
æä¸ç§å建æ¹æ³ï¼
//带cancelè¿åå¼çContext,ä¸æ¦cancel被è°ç¨,å³åæ¶è¯¥å建çcontextfuncWithCancel(parentContext)(ctxContext,cancelCancelFunc)//带æææcancelè¿åå¼çContext,å³å¿ é¡»å°è¾¾æå®æ¶é´ç¹è°ç¨çcacelæ¹æ³æä¼è¢«æ§è¡funcWithDeadline(parentContext,deadlinetime.Time)(Context,CancelFunc)//å¸¦è¶ æ¶æ¶é´cancelè¿åå¼çContext,类似Deadline,åè æ¯æ¶é´ç¹,åè 为æ¶é´é´é//ç¸å½äºWithDeadline(parent,time.Now().Add(timeout)).funcWithTimeout(parentContext,timeouttime.Duration)(Context,CancelFunc)ä¸é¢æ¥çæ¹ç¼èªAdvanced Go Concurrency Patternsè§é¢æä¾çä¸ä¸ªç®åä¾åï¼
packagemainimport("context""fmt""time")funcsomeHandler(){ //å建继æ¿Backgroundçåèç¹Contextctx,cancel:=context.WithCancel(context.Background())godoSth(ctx)//模æç¨åºè¿è¡-Sleep5ç§time.Sleep(5*time.Second)cancel()}//æ¯1ç§workä¸ä¸,åæ¶ä¼å¤æctxæ¯å¦è¢«åæ¶,å¦ææ¯å°±éåºfuncdoSth(ctxcontext.Context){ vari=1for{ time.Sleep(1*time.Second)select{ case<-ctx.Done():fmt.Println("done")returndefault:fmt.Printf("work%dseconds:\n",i)}i++}}funcmain(){ fmt.Println("start...")someHandler()fmt.Println("end.")}è¾åºç»æï¼
注æ,æ¤æ¶doSthæ¹æ³ä¸caseä¹doneçfmt.Println("done")并没æ被æå°åºæ¥.
è¶ æ¶åºæ¯ï¼
packagemainimport("context""fmt""time")functimeoutHandler(){ //å建继æ¿Backgroundçåèç¹Contextctx,cancel:=context.WithTimeout(context.Background(),3*time.Second)godoSth(ctx)//模æç¨åºè¿è¡-Sleepç§time.Sleep(*time.Second)cancel()//3ç§åå°æååæ¶doSthgoroutine}//æ¯1ç§workä¸ä¸,åæ¶ä¼å¤æctxæ¯å¦è¢«åæ¶,å¦ææ¯å°±éåºfuncdoSth(ctxcontext.Context){ vari=1for{ time.Sleep(1*time.Second)select{ case<-ctx.Done():fmt.Println("done")returndefault:fmt.Printf("work%dseconds:\n",i)}i++}}funcmain(){ fmt.Println("start...")timeoutHandler()fmt.Println("end.")}è¾åºç»æï¼
4 contextæ¯ä¸ä¸ªä¼é ç设计å?ç¡®å®,éè¿å¼å ¥Contextå ,ä¸ä¸ªrequestèå´å æægoroutineè¿è¡æ¶çåæ¶å¯ä»¥å¾å°æRæçæ§å¶.ä½æ¯è¿ç§è§£å³æ¹å¼å´ä¸å¤ä¼é .
4.1 context åç æ¯ä¸æ ·æ©æ£ä¸æ¦ä»£ç ä¸æå¤ç¨å°äºContext,ä¼ éContextåéï¼é常ä½ä¸ºå½æ°ç第ä¸ä¸ªåæ°ï¼ä¼åç æ¯ä¸æ ·è延å¨åå¤è°ç¨å®çå°æ¹. æ¯å¦å¨ä¸ä¸ªrequestä¸å®ç°æ°æ®åºäºå¡æè åå¸å¼æ¥å¿è®°å½, å建çcontext,ä¼ä½ä¸ºåæ°ä¼ éå°ä»»ä½ææ°æ®åºæä½ææ¥å¿è®°å½éæ±çå½æ°ä»£ç å¤. å³æ¯ä¸ä¸ªç¸å ³å½æ°é½å¿ é¡»å¢å ä¸ä¸ªcontext.Contextç±»åçåæ°,ä¸ä½ä¸ºç¬¬ä¸ä¸ªåæ°,è¿å¯¹æ å ³ä»£ç å®å ¨æ¯ä¾µå ¥å¼ç.
æ´å¤è¯¦ç»å 容å¯åè§ï¼Michal Strba çcontext-should-go-away-go2æç«
Google Groupä¸ç讨论å¯ç§»æ¥è¿é.
4.2 Context ä¸ä» ä» åªæ¯cancelä¿¡å·Contextæºå¶ææ ¸å¿çåè½æ¯å¨goroutineä¹é´ä¼ écancelä¿¡å·,ä½æ¯å®çå®ç°æ¯ä¸å®å ¨ç.
Cancelå¯ä»¥ç»å为主å¨ä¸è¢«å¨ä¸¤ç§,éè¿ä¼ écontextåæ°,让è°ç¨goroutineå¯ä»¥ä¸»å¨cancel被è°ç¨goroutine.ä½æ¯å¦ä½å¾ç¥è¢«è°ç¨goroutineä»ä¹æ¶åæ§è¡å®æ¯,è¿é¨åContextæºå¶æ¯æ²¡æå®ç°ç.èç°å®ä¸çç¡®åæä¸äºè¿æ ·çåºæ¯,æ¯å¦ä¸ä¸ªç»è£ æ°æ®çgoroutineå¿ é¡»çå¾ å ¶ä»goroutineå®ææå¯å¼å§æ§è¡,è¿æ¯contextææ¾ä¸å¤ç¨äº,å¿ é¡»åå©sync.WaitGroup.
funcserve(lnet.Listener)error{ varwgsync.WaitGroupvarconnnet.Connvarerrerrorfor{ conn,err=l.Accept()iferr!=nil{ break}wg.Add(1)gofunc(cnet.Conn){ deferwg.Done()handle(c)}(conn)}wg.Wait()returnerr}4.3 context.valuecontext.Valueç¸å½äºgoroutineçTLSï¼Thread Local Storageï¼,ä½å®ä¸æ¯éæç±»åå®å ¨ç,ä»»ä½ç»æä½åéé½å¿ é¡»ä½ä¸ºå符串形å¼åå¨.åæ¶,ææcontexté½ä¼å¨å ¶ä¸å®ä¹åé,å¾å®¹æé æå½åå²çª.
5 æ»ç»contextå éè¿æ建æ åå ³ç³»çContext,æ¥è¾¾å°ä¸ä¸å±Goroutineè½å¯¹ä¼ éç»ä¸ä¸å±Goroutineçæ§å¶.对äºå¤çä¸ä¸ªRequest请æ±æä½,éè¦éç¨contextæ¥å±å±æ§å¶Goroutine,以åä¼ éä¸äºåéæ¥å ±äº«.
Context对象ççåå¨æä¸è¬ä» 为ä¸ä¸ªè¯·æ±çå¤çå¨æ.å³é对ä¸ä¸ªè¯·æ±å建ä¸ä¸ªContextåéï¼å®ä¸ºContextæ ç»æçæ ¹ï¼;å¨è¯·æ±å¤çç»æå,æ¤éæ¤ctxåé,éæ¾èµæº.
æ¯æ¬¡å建ä¸ä¸ªGoroutine,è¦ä¹å°åæçContextä¼ éç»Goroutine,è¦ä¹å建ä¸ä¸ªåContextå¹¶ä¼ éç»Goroutine.
Contextè½çµæ´»å°åå¨ä¸åç±»å,ä¸åæ°ç®çå¼,并ä¸ä½¿å¤ä¸ªGoroutineå®å ¨å°è¯»åå ¶ä¸çå¼.
å½éè¿ç¶Context对象å建åContext对象æ¶,å¯åæ¶è·å¾åContextçä¸ä¸ªæ¤éå½æ°,è¿æ ·ç¶Context对象çå建ç¯å¢å°±è·å¾äºå¯¹åContextå°è¦è¢«ä¼ éå°çGoroutineçæ¤éæ.
å¨åContextè¢«ä¼ éå°çgoroutineä¸,åºè¯¥å¯¹è¯¥åContextçDoneä¿¡éï¼channelï¼è¿è¡çæ§,ä¸æ¦è¯¥ä¿¡éè¢«å ³éï¼å³ä¸å±è¿è¡ç¯å¢æ¤éäºæ¬goroutineçæ§è¡ï¼,åºä¸»å¨ç»æ¢å¯¹å½å请æ±ä¿¡æ¯çå¤ç,éæ¾èµæºå¹¶è¿å.
6 è´è°¢pkg/context
context-should-go-away-go2
ç解 Go Context æºå¶
context-isnt-for-cancellation
context-is-for-cancelation
thread-local-a-convenient-abomination