location /
}(一) set行的解析
1. 我們首先看這裡這句:
為什麼這個函式的第三個引數flag,被設定成ngx_http_var_changeable,那是因為set之後的第乙個的變數可以在乙個if配置裡面出現多次,每次可以改變它的值,當然還有nochangeable的,後面碰到再說。緊接著,把這個變數放到全域性變數陣列中,同時記錄它的所在位置(即下標index),即函式ngx_http_get_variable_index。
2. 通過圖中所示,先處理的是set後面的第二個變數,那第乙個怎麼辦呢?先處理它使用原因的,一會就可以看到了。這個變數通過ngx_http_rewrite_value函式來處理的,在處理時帶有$的變數,nginx裡面稱作「complex value」,於是分配ngx_http_script_complex_value_code_t結構同時使用ngx_http_script_complex_value_code來處理,接下來有幾行**需要注意下:
// lengths和values陣列會在ngx_http_script_compile的執行過程中被填充
sc.lengths = &complex->lengths;
sc.values = &lcf->codes;
// complete_lengths置1,是為了給lengths陣列結尾(以null指標填充),因為在運
// 行這個陣列中的成員時,碰到null時,執行就結束了。
sc.complete_lengths = 1;
3. ngx_http_script_compile函式算是這裡的乙個核心,主要是分離當前「complex value」中的一些不同型別的變數,具體邏輯不難看懂,我們只把一些需要注意的地方強調下就行了。
在開始的時候有個函式叫ngx_http_script_init_arrays,這個函式對flushes,lengths和values三個陣列的初始容量給出了乙個估計值,當然nginx的陣列結構在初始空間不夠的時候會自動擴充的,這個就不用太追究了。
在函式ngx_http_script_add_capture_code中,有個這樣的賦值動作code->n = 2 * n,為什麼是2*n呢?這個跟pcre儲存匹配結果集的結構有關,後面我們會講到。
4. 在處理set 中的第乙個引數的時候,它的handler被置為了ngx_http_script_set_var_code,通過這個函式,我們也就知道了為什麼要先處理後乙個引數:
// e->ip就是之前在解析時設定的各種結構體
// e->sp是通過解析得到的變數處理結果的乙個陣列,變數的放置順序跟
// ip中的順序一致,而且隨著處理而遞增,所以為了保持中處理的一致性(這樣
// 就可以保證許多地方使用一致的處理方式)。這裡sp—就可以得到之前的處
// 理值,得到我們想要的結果了。
e->sp--;
r->variables[code->index].len = e->sp->len;
r->variables[code->index].valid = 1;
r->variables[code->index].no_cacheable = 0;
r->variables[code->index].not_found = 0;
r->variables[code->index].data = e->sp->data;
(二) rewrite行的解析
有了前面對if和set的介紹,rewrite分析起來就簡單多了,大多數的處理前面都已經出現過了,這裡只說幾個重點。
1. 在rewrite後面第二個引數中,凡是以「http://」,「https://」,「$scheme」,或者是最後的引數是「redirect」的,在後續的處理都是產生302的響應,其次最後的引數裡,如「permanent」會產生301響應,last和break將會產生nginx內部的重定向(相當於重新做一次http的請求),會重新進行location的匹配等,但是它們的區別在於break在重定向時,就不會在做重定向的處理,而last將會繼續。
2. 對於rewrite後面第二個引數的處理,跟處理set中第二個變數的過程是大致一樣的。需要強調的有以下幾點:
// 剛開始的時候已經給regex做了初始化,為什麼後面有重新賦值了一次呢?原因就是「它可能變了」。。。
對於上面這個問題,可以追溯到ngx_http_script_add_code函式,我們知道nginx在對陣列push時,如果發現空間不足會做擴充,在擴充時會分配原來兩倍大小的空間,並把原有資料copy過來。這樣一樣原來執行這個陣列中的一些指標值此時就不能再用了,而要指向他們的「新家」,這也就是這裡regex重新賦值以及以®ex為引數傳遞給ngx_http_script_add_code的目的所在。
3. 到這裡我們的if指令到了結束的時候,那麼就以乙個null來做結尾。
if (last)
*code = null;
}看最後這一句:
regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - (u_char *) regex;
這裡其實說明了當前位置距離codes陣列的大小,這樣在必要的時候,例如e->ip += code->next,跳過當前結構去處理下乙個,很方便。
到這裡,基本的輪廓就是這樣子,至於各個handler的執行細節,大家可以自己去閱讀**,提示一點的是,要結合e->ip,e->sp等,ngx_http_script_engine_t結構中的一些成員來看,就容易懂了。
nginx指令碼引擎與設計設計 三
這一部分我們將 一些較細節的東西,加上前面 一 二 兩篇文章對典型情景的分析,我相信應該會對大家理解nginx的指令碼解析機制有很大的幫助的。這裡我們關注ngx http core main conf t 下面簡寫為cmcf 結構中的這兩個成員,cmcf variables keys和cmcf va...
引擎學習之二 設計引擎
1 建立動態和靜態鏈結庫 lib hinstance loadlibrary lpctstr plibfilename zfxrenderer.cpp zfxrenderer.h 建立,得到,釋放 zfxrenderdevice.h 用於定義介面 確保載入到記憶體中的dll只載入一次,如果另乙個應用...
再談nginx變數 二
nginx中除了一些內建變數,自定義變數 通過set指令定義的 還有一模擬較特別的變數,我稱它們為特殊字首變數,這類變數多數在 內建變數陣列內是找不到的,形式可以分一下幾類 其中有些常見的http 和sent http 其實主要是一些header 在內建變數陣列中已經給出,多數偏僻的則沒有指明,所以...