nginx的指令碼引擎(一)
nginx的指令碼的語法和shell是很像的,我大致看了一下覺得挺有意思的,就想寫寫記錄一下。我沒看過shell指令碼的引擎,不知道nginx指令碼引擎和shell指令碼引擎像不像,但是我覺得nginx的指令碼引擎有點像C和彙編。
ngx_http_script_engine_t這個結構就代表了一段指令碼,ip指向的是編譯好的指令碼,sp指向的是一塊記憶體用來儲存指令碼執行的時候產生的一些中間值。ip/sp從名字看就已經很像彙編了instruction pointer/stack pointer指令暫存器和棧暫存器呀,當然是我瞎猜的,有時間的話可以查一下官方文件。程式碼段裡的各個指令長度不一定相同。
再來說說編譯過程,編譯過程是在nginx_http_script_engine_t建立之前執行的,我先畫出了整個圖是為了更好理解。舉個set指令編譯的的例子,比如你在腳本里有這樣的程式碼set $foo helloworld,指令碼編譯的步驟如下:
第一步:首先在cmcf->variables_keys和cmcf->variables裡增加一個變數foo,這個變數是可寫的。我之前寫的nginx的變數系統裡只說了變數的讀取方法,差別不大。
第二步:把ngx_http_script_value_code_t指令放到程式碼段裡(code欄位是一個回撥函式,賦值成ngx_http_script_value_code),把ngx_http_script_var_code_t指令放到程式碼段裡(code欄位是一個回撥函式,賦值成ngx_http_script_set_var_code)。
第三步:http請求來的時候會在rewrite階段會按順序執行ip指向的這一段程式碼,也就是執行ngx_http_script_value_code和ngx_http_script_set_var_code函式。
我們看一下這兩個函式做了什麼
void ngx_http_script_value_code(ngx_http_script_engine_t *e) { ngx_http_script_value_code_t *code; code = (ngx_http_script_value_code_t *) e->ip; e->ip += sizeof(ngx_http_script_value_code_t); e->sp->len = code->text_len; e->sp->data = (u_char *) code->text_data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script value: \"%v\"", e->sp); e->sp++; }
void ngx_http_script_set_var_code(ngx_http_script_engine_t *e) { ngx_http_request_t *r; ngx_http_script_var_code_t *code; code = (ngx_http_script_var_code_t *) e->ip; e->ip += sizeof(ngx_http_script_var_code_t); r = e->request; 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; }
第一條指令把“helloworld”這個字串放到了sp裡,第二條指令把值從sp裡取出來存到了變數系統的foo變數裡,任務完成,看起來很簡單。
set指令還可以這樣用set $foo $x$y,這就是所謂的變數插值,過程和上面這個類似,只不過第一條指令是先從變數系統裡取出$x和$y的值,再放入sp裡。
今天先寫這麼多,高興了再分析別的指令。