日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

transform插件

發布時間:2025/3/21 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 transform插件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

transform插件用于修改POST請求的body和http響應的body,可以理解為一個過濾器,或者nginx的body_filter。

有兩個地方可以添加transform回調函數,TS_HTTP_REQUEST_TRANSFORM_HOOK和TS_HTTP_RESPONSE_TRANSFORM_HOOK,分別是過濾POST請求的body和http響應的body。在適當的hook點判斷是否需要使transform邏輯生效,需要的話在相應的transform hook點添加回調函數。比如這樣一個場景,在緩存查詢結束的時候判斷查詢結果是hit還是miss,miss的話需要在http響應body末尾添加一些內容,這樣響應的內容連同被添加的內容會當成整個的響應內容被緩存住,后續的請求如果在緩存查詢結束判斷查詢結果是hit就會將transform后的結果響應出去。

有兩個vio,input_vio(write vio)和output_vio(read vio)。每個vio都有配套的TSIOBuffer和TSIOBufferReader一起工作。

數據的流向是input_vio->分片插件->output_vio。transform插件對應一個continuation和一個回調函數,假設這個回調函數叫plutin_handler,plutin_handler根據不同的event有不同的邏輯。分片插件每transform一些東西,都會觸發上游的TS_EVENT_VCONN_WRITE_READY事件通知上游可以繼續發送東西過來,并且觸發下游的TS_EVENT_IMMEDIATE事件通知下游有東西可以讀了。如果分片插件判斷已經沒有數據需要繼續處理了,會觸發上游的TS_EVENT_VCONN_WRITE_COMPLETE事件,并且觸發下游的TS_EVENT_IMMEDIATE事件?;蛘呖梢赃@樣理解。整個流程分為三部分,上游,分片插件,下游。下游處理完數據會通過TSContCall觸發上游的TS_EVENT_VCONN_WRITE_READY或TS_EVENT_VCONN_WRITE_COMPLETE事件,上游準備好了數據會通過TSVIOReenable觸發下游的TS_EVENT_IMMEDIATE事件。

ats插件的編譯:tsxs -o hello-world.so -c hello-world.c,注意tsxs要使用與其它可執行文件配套一起生成的,不然的話會出錯。


重點函數:

TSVConnWrite:

tsapi TSVIO TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbytes);

生成一個vio,有什么操作的話會觸發contp,要寫的字節數就是nbytes


TSVConnWriteVIOGet:

tsapi TSVIO TSVConnWriteVIOGet(TSVConn connp);

獲取一個VConnection的input_vio(write_vio),VConnection是input_vio的實施者


TSVIOContGet:

tsapi TSCont TSVIOContGet(TSVIO viop);

獲取一個vio的continuation,continuation是vio的使用者,是transform的上游


TSTransformOutputVConnGet:

tsapi TSVConn TSTransformOutputVConnGet(TSVConn connp);

獲取一個下游的VConnection


TSVIONDoneGet:

tsapi TSIOBuffer TSVIOBufferGet(TSVIO viop);

獲取一個vio已經操作完成的字節數


TSVIONBytesSet:

tsapi void TSVIONBytesSet(TSVIO viop, int64_t nbytes);

設置這個vio將要處理的字節數,第二個參數要比TSVIONDoneGet得到的結果大


TSVIONBytesGet:

tsapi int64_t TSVIONBytesGet(TSVIO viop);

獲取這個vio將要處理的字節數


TSIOBufferCopy:

tsapi int64_t TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset);

將內容從一個TSIOBufferReader拷貝到一個TSIOBuffer,拷貝的字節數是length,偏移量是offset


TSIOBufferReaderConsume:

tsapi void TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes);

拷貝操作結束后要執行這個函數,要消費input_vio指定字節數


TSVIONDoneSet:

tsapi void TSVIONDoneSet(TSVIO viop, int64_t ndone);

拷貝操作結束后要執行這個函數,要告知input_vio已經消費了多少字節


TSVConnClosedGet:

tsapi int TSVConnClosedGet(TSVConn connp);

判斷connp是否已經被關閉,connp是transform插件本身的contiuation


如下是一個完整的transform插件,實現的功能是在讀源站的響應頭時添加transform插件。如果緩存查詢結果是hit則不需要回源,也就不會添加transform插件了。插件的邏輯是在響應末尾添加"hello world\n"字符串。

#include?<limits.h> #include?<stdio.h> #include?<string.h> #include?<ts/ts.h>#define?ASSERT_SUCCESS(_x)?TSAssert?((_x)?==?TS_SUCCESS)typedef?struct?{TSVIO?output_vio;TSIOBuffer?output_buffer;TSIOBufferReader?output_reader;int?append_needed; }?MyData;static?TSIOBuffer?append_buffer; static?TSIOBufferReader?append_buffer_reader; static?int?append_buffer_length;static?MyData?* my_data_alloc()?{MyData?*data;data?=?(MyData?*)?TSmalloc(sizeof(MyData));TSReleaseAssert(data);data->output_vio?=?NULL;data->output_buffer?=?NULL;data->output_reader?=?NULL;data->append_needed?=?1;return?data; }static?void?my_data_destroy(MyData?*?data)?{if?(data)?{if?(data->output_buffer)TSIOBufferDestroy(data->output_buffer);TSfree(data);} }static?void?handle_transform(TSCont?contp)?{TSVConn?output_conn;TSVIO?write_vio;MyData?*data;int64_t?towrite;int64_t?avail;/*獲取transform插件的下游VConnection,這個VConnection會接收transform插件的處理完的數據這個VConnection會觸發contp的TS_EVENT_VCONN_WRITE_READY,TS_EVENT_VCONN_WRITE_COMPLETE或TS_EVENT_ERROR事件*/output_conn?=?TSTransformOutputVConnGet(contp);/*獲取input_vio,通過input_vio可以獲取到input_buffer*/write_vio?=?TSVConnWriteVIOGet(contp);/*獲取這個contp的數據,沒有的話初始化并且TSContDataSet*/data?=?TSContDataGet(contp);if?(!data)?{towrite?=?TSVIONBytesGet(write_vio);if?(towrite?!=?INT64_MAX)?{towrite?+=?append_buffer_length;}data?=?my_data_alloc();data->output_buffer?=?TSIOBufferCreate();data->output_reader?=?TSIOBufferReaderAlloc(data->output_buffer);/*獲取output_vio,并且指定要向其傳送的字節數,字節數就是http響應body的長度加上"hello?world\n"的長度*/data->output_vio?=?TSVConnWrite(output_conn,?contp,?data->output_reader,?towrite);TSContDataSet(contp,?data);}/*如果input_buffer已經為空,說明上游不會再有數據傳到transform插件*/if?(!TSVIOBufferGet(write_vio))?{if?(data->append_needed)?{data->append_needed?=?0;TSIOBufferCopy(TSVIOBufferGet(data->output_vio),?append_buffer_reader,?append_buffer_length,?0);}TSVIONBytesSet(data->output_vio,?TSVIONDoneGet(write_vio)?+?append_buffer_length);TSVIOReenable(data->output_vio);return;}/*獲取還有多少數據需要處理,也即還有多少東西會從上游發送來到transform插件*/towrite?=?TSVIONTodoGet(write_vio);if?(towrite?>?0)?{avail?=?TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));if?(towrite?>?avail)?{towrite?=?avail;}if?(towrite?>?0)?{TSIOBufferCopy(TSVIOBufferGet(data->output_vio),?TSVIOReaderGet(write_vio),?towrite,?0);TSIOBufferReaderConsume(TSVIOReaderGet(write_vio),?towrite);TSVIONDoneSet(write_vio,?TSVIONDoneGet(write_vio)?+?towrite);}}/*獲取還有多少數據需要處理,也即還有多少東西會從上游發送來到transform插件*/if?(TSVIONTodoGet(write_vio)?>?0)?{/*如果上游還有數據需要傳送*/if?(towrite?>?0)?{/*通知下游可以讀數據了*/TSVIOReenable(data->output_vio);/*如果上游尚有數據會發送過來,需要通知上游可以繼續發送數據了*/TSContCall(TSVIOContGet(write_vio),?TS_EVENT_VCONN_WRITE_READY,?write_vio);}}else?{/*如果上游已經沒有更多的數據,需要執行append的邏輯了,也即將"hello?world\n"添加到響應數據末尾*/if?(data->append_needed)?{data->append_needed?=?0;TSIOBufferCopy(TSVIOBufferGet(data->output_vio),?append_buffer_reader,?append_buffer_length,?0);}/*設置output_vio需要處理的字節數,這樣output_vio處理完這些內容就可以發送TS_EVENT_VCONN_WRITE_COMPLETE給transform插件了*/TSVIONBytesSet(data->output_vio,?TSVIONDoneGet(write_vio)?+?append_buffer_length);/*通知下游可以讀數據了*/TSVIOReenable(data->output_vio);/*如果上游尚有數據會發送過來,需要通知上游可以繼續發送數據了*/TSContCall(TSVIOContGet(write_vio),?TS_EVENT_VCONN_WRITE_COMPLETE,?write_vio);} }static?int?append_transform(TSCont?contp,?TSEvent?event,?void?*edata)?{/*如果transform插件已經被關閉,需要釋放資源*/if?(TSVConnClosedGet(contp))?{my_data_destroy(TSContDataGet(contp));TSContDestroy(contp);return?0;}?else?{switch?(event)?{case?TS_EVENT_ERROR:?{TSVIO?write_vio;write_vio?=?TSVConnWriteVIOGet(contp);/*通知上游出錯了*/TSContCall(TSVIOContGet(write_vio),?TS_EVENT_ERROR,?write_vio);}break;case?TS_EVENT_VCONN_WRITE_COMPLETE:/*如果下游觸發了TS_EVENT_VCONN_WRITE_COMPLETE事件,需要關閉下游的VConnection*/TSVConnShutdown(TSTransformOutputVConnGet(contp),?0,?1);break;case?TS_EVENT_VCONN_WRITE_READY:default:handle_transform(contp);break;}}return?0; }static?int?transformable(TSHttpTxn?txnp)?{TSMBuffer?bufp;TSMLoc?hdr_loc;TSHttpStatus?resp_status;TSHttpTxnServerRespGet(txnp,?&bufp,?&hdr_loc);//判斷源站給的狀態碼,只有源站返回200時才會執行transform邏輯if?(TS_HTTP_STATUS_OK?==?(resp_status?=?TSHttpHdrStatusGet(bufp,?hdr_loc)))?{ASSERT_SUCCESS(TSHandleMLocRelease(bufp,?TS_NULL_MLOC,?hdr_loc));return?1;}?else?{ASSERT_SUCCESS(TSHandleMLocRelease(bufp,?TS_NULL_MLOC,?hdr_loc));return?0;} }static?int?transform_plugin(TSCont?contp,?TSEvent?event,?void?*edata)?{TSHttpTxn?txnp?=?(TSHttpTxn)?edata;switch?(event)?{case?TS_EVENT_HTTP_READ_RESPONSE_HDR://只有緩存查詢結果為miss的時候才會回源,才會執行這個case的邏輯if(transformable(txnp)){TSVConn?connp;connp?=?TSTransformCreate(append_transform,?txnp);TSHttpTxnHookAdd(txnp,?TS_HTTP_RESPONSE_TRANSFORM_HOOK,?connp);}TSHttpTxnReenable(txnp,?TS_EVENT_HTTP_CONTINUE);return?0;default:break;}return?0; }static?int?data_prepared()?{append_buffer?=?TSIOBufferCreate();append_buffer_reader?=?TSIOBufferReaderAlloc(append_buffer);TSIOBufferWrite(append_buffer,?"hello?world\n",?sizeof("hello?world\n")?-?1);append_buffer_length?=?TSIOBufferReaderAvail(append_buffer_reader);return?1; }int?check_ts_version()?{const?char?*ts_version?=?TSTrafficServerVersionGet();int?result?=?0;if?(ts_version)?{int?major_ts_version?=?0;int?minor_ts_version?=?0;int?patch_ts_version?=?0;if?(sscanf(ts_version,?"%d.%d.%d",?&major_ts_version,?&minor_ts_version,?&patch_ts_version)?!=?3)?{return?0;}if?(major_ts_version?>=?2)?{result?=?1;}}return?result; }void?TSPluginInit(int?argc,?const?char?*argv[])?{TSPluginRegistrationInfo?info;info.plugin_name?=?"append-transform";info.vendor_name?=?"MyCompany";info.support_email?=?"ts-api-support@MyCompany.com";if?(TSPluginRegister(TS_SDK_VERSION_3_0,?&info)?!=?TS_SUCCESS)?{TSError("Plugin?registration?failed.\n");goto?Lerror;}if?(!check_ts_version())?{TSError("Plugin?requires?Traffic?Server?3.0?or?later\n");goto?Lerror;}if?(!data_prepared())?{TSError("[append-transform]?Failed?to?prepared?data\n");goto?Lerror;}TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK,TSContCreate(transform_plugin,?NULL));return;Lerror:TSError("[append-transform]?Unable?to?initialize?plugin\n"); }


轉載于:https://blog.51cto.com/11490450/1876931

總結

以上是生活随笔為你收集整理的transform插件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 无码粉嫩虎白一线天在线观看 | 日产国产亚洲精品系列 | 91综合视频 | 国产一区二区三区自拍 | 人人超碰在线 | 性午夜| av在线男人天堂 | 免费av一级片 | 精品久久人妻av中文字幕 | 国产精品videossex久久发布 | 国产男女猛烈无遮挡免费视频 | 成人在线精品视频 | 国内精品偷拍视频 | 国产日韩av在线播放 | 国产精品午夜福利视频234区 | 日本韩国欧美一区 | 骚狐网站 | 脱裤吧导航 | 午夜免费一级片 | 国产主播啪啪 | 欧美高清精品一区二区 | 欧美www| 欧美日韩四区 | 成人日b视频 | 欧美成人免费视频 | 护士的小嫩嫩好紧好爽 | 亚洲久久久 | 我想看一级黄色片 | 羞羞在线观看 | 国产在线123 | 欧美人与动性xxxxx杂性 | 午夜激情小视频 | 一级中国毛片 | 色啪网站 | 欧美大片免费观看网址 | 综合精品一区 | 久久五月视频 | 少妇性xxxxxxxxx色武功 | 国产夫妻视频 | 综合精品久久 | 波多野结衣视频免费看 | 日韩在线第一 | av毛片在线免费观看 | 黄色资源网 | 国产福利免费在线观看 | 亚洲av无码一区二区三区在线播放 | 婷婷国产成人精品视频 | 无码人妻一区二区三区精品视频 | 激情吧| 95香蕉视频 | 色妞www精品视频 | 久久er99热精品一区二区介绍 | 高清国产在线观看 | 国产精品6666| 天堂精品 | 丰满人妻一区二区三区精品高清 | 日本大尺度床戏揉捏胸 | 无码无遮挡又大又爽又黄的视频 | 91爱爱爱 | 国产精品视频免费网站 | 亚洲成人少妇 | 欧美日韩精品在线视频 | 黄色大片aa | 日日艹夜夜艹 | 91久久久久一区二区 | 日韩大片在线免费观看 | 午夜黄色影院 | 国产人妻精品久久久久野外 | 涩涩视频在线看 | 国产日韩欧美精品在线观看 | 19禁大尺度做爰无遮挡电影 | 久久影片 | 伊人自拍 | 国产视频精品视频 | 国产91大片 | 精品欧美激情精品一区 | 亚洲一线视频 | 美日韩一区二区三区 | 亚洲av成人精品日韩在线播放 | 精品国产乱码久久久久 | 综合中文字幕 | 日韩黄色免费看 | 午夜黄色网址 | 人人干狠狠干 | 99久久久久成人国产免费 | 催眠调教艳妇成肉便小说 | 91污片| 日韩毛片视频 | 就要干就要操 | 超碰在线人人 | 精品少妇人妻av一区二区三区 | 欧美日韩一区二区三区在线播放 | 欧美r级在线 | 亚洲激情二区 | 亚洲美女性视频 | 欧美一级淫片007 | 中文字幕被公侵犯的漂亮人妻 | 久久精品久久久久久 | 熟女少妇内射日韩亚洲 |