WebサーバとしてのNginxの調査結果を記録する。


ngx_http_handler関数

HTTP処理を始めるはず・・・POSTだった場合の受信がまだですがこの関数では
HTTPヘッダの値からkeepAliveを使うか、Content-Lengthヘッダがあるかなどのチェックをしています。


    719 void
    720 ngx_http_handler(ngx_http_request_t *r)
    721 {
    722     ngx_http_core_main_conf_t  *cmcf;
    723
    724     r->connection->log->action = NULL;
    725
    726     r->connection->unexpected_eof = 0;
    727
    728     if (!r->internal) {
    729         switch (r->headers_in.connection_type) {
    730         case 0:
    731             if (r->http_version > NGX_HTTP_VERSION_10) {
    732                 r->keepalive = 1;
    733             } else {
    734                 r->keepalive = 0;
    735             }
    736             break;
    737
    738         case NGX_HTTP_CONNECTION_CLOSE:
    739             r->keepalive = 0;
    740             break;
    741
    742         case NGX_HTTP_CONNECTION_KEEP_ALIVE:
    743             r->keepalive = 1;
    744             break;
    745         }
    746
    747         if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) {
    748
    749             /*
    750              * MSIE may wait for some time if an response for
    751              * a POST request was sent over a keepalive connection
    752              */
    753
    754             r->keepalive = 0;
    755         }
    756
    757         if (r->headers_in.content_length_n > 0) {
    758             r->lingering_close = 1;
    759
    760         } else {
    761             r->lingering_close = 0;
    762         }
    763
    764         r->phase_handler = 0;
    765
    766     } else {
    767         cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    768         r->phase_handler = cmcf->phase_engine.server_rewrite_index;
    769     }
    770
    771     if (r->unparsed_uri.len) {
    772         r->valid_unparsed_uri = 1;
    773     }
    774
    775     r->valid_location = 1;
    776 #if (NGX_HTTP_GZIP)
    777     r->gzip_tested = 0;
    778     r->gzip_ok = 0;
    779     r->gzip_vary = 0;
    780 #endif
    781
    782     r->write_event_handler = ngx_http_core_run_phases;
    783     ngx_http_core_run_phases(r);
    784 }

r->internalは、内部リダイレクトやサブリクエストであれば1が入っています。
通常のリクエスト処理では0のままなので、728行目のif文では真になります。

リクエストヘッダのConnectionヘッダを見てkeepAliveを使うか判断しているようです。
Connectionヘッダがない場合はHTTPバージョンで、HTTP1.1ならKeepAliveを使うと判断していますね。

次の747行目の処理が面白い。
ブラウザ(User-Agent)がIEで、POSTだったらKeepAliveをoffにすると。
ソース直書きでこういうことするんですね、Nginxって。
Apacheではデフォルトのhttpd.confでSSLのときブラウザがIEならKeepAliveをoffって設定がありますが
こちらは設定ファイルなのでサーバ管理者が設定変更すればIEでも許容できます。
Nginxではソースに書かれてしまっているから、問答無用でkeepAlive offですね。

757行目では、リクエストヘッダのContent-Lengthヘッダの有無を見ています。
値があればr->lingering_close = 1をセット。
これはあとでPOSTデータを取得するためでしょう。

r->phase_handler = 0 は何の意味があるのか不明です。
r->internal == 1 のときr->phase_handlerになにやら値が入っていますね。ううむ。

771行目、リクエストURLの長さが1以上であればvalid_unparsed_uri = 1がセット。
正常なリクエストである限り、1がセットされることになります。

続いて処理はngx_http_core_run_phases(r)へと続いていきます。


ngx_http_core_run_phases関数


短いですが、パッと見まったくわからない関数です。

    787 void
    788 ngx_http_core_run_phases(ngx_http_request_t *r)
    789 {
    790     ngx_int_t                   rc;
    791     ngx_http_phase_handler_t   *ph;
    792     ngx_http_core_main_conf_t  *cmcf;
    793
    794     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    795
    796     ph = cmcf->phase_engine.handlers;
    797
    798     while (ph[r->phase_handler].checker) {
    799
    800         rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
    801
    802         if (rc == NGX_OK) {
    803             return;
    804         }
    805     }
    806 }

一つ一つ見てみましょう。
ngx_http_get_module_main_confはマクロです。
#define ngx_http_get_module_main_conf(r, module)                             \
    (r)->main_conf[module.ctx_index]
これでngx_http_core_moduleに関する設定の構造体のアドレスがcmcfに返ります。
ngx_http_core_main_conf_tの型は以下のとおりです。

typedef struct {
    ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */

    ngx_http_phase_engine_t    phase_engine;

    ngx_hash_t                 headers_in_hash;

    ngx_hash_t                 variables_hash;

    ngx_array_t                variables;       /* ngx_http_variable_t */

    ngx_uint_t                 server_names_hash_max_size;
    ngx_uint_t                 server_names_hash_bucket_size;

    ngx_uint_t                 variables_hash_max_size;
    ngx_uint_t                 variables_hash_bucket_size;

    ngx_hash_keys_arrays_t    *variables_keys;

    ngx_uint_t                 try_files;       /* unsigned  try_files:1 */

    ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

typedef struct {
    ngx_http_phase_handler_t  *handlers;
    ngx_uint_t                 server_rewrite_index;
    ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;

typedef struct ngx_http_phase_handler_s  ngx_http_phase_handler_t;

struct ngx_http_phase_handler_s {
    ngx_http_phase_handler_pt  checker;
    ngx_http_handler_pt        handler;
    ngx_uint_t                 next;
};

typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph);

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,

    NGX_HTTP_SERVER_REWRITE_PHASE,

    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,

    NGX_HTTP_PREACCESS_PHASE,

    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,

    NGX_HTTP_TRY_FILES_PHASE,
    NGX_HTTP_CONTENT_PHASE,

    NGX_HTTP_LOG_PHASE
} ngx_http_phases;

絵にしてみた。


796行目でphにhandlers構造体のポインタが入ります。

次のwhile文では、chekerに関数が登録されているか、登録されている関数に飛んでOKが返らない限り
繰り返されるwhile文です。
r->phase_handlerは今のフェーズです。enumに定義されていますが、0ならNGX_HTTP_POST_READ_PHASE
これから何か処理してフェーズが終わるとr->phase_handler ++;となるのでしょう。

今はNGX_HTTP_POST_READ_PHASEです。
ngx_http_phase_handler_pt checkerに登録されている関数に飛ぶことになります。
登録されている関数はngx_http_core_generic_phase()です。

ngx_http_core_generic_phaseは以下のとおり。
ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
    ngx_int_t  rc;

    /*
     * generic phase checker,
     * used by the post read, server rewrite, rewrite, and pre-access phases
     */

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "generic phase: %ui", r->phase_handler);

    rc = ph->handler(r);

    if (rc == NGX_OK) {
        r->phase_handler = ph->next;
        return NGX_AGAIN;
    }

    if (rc == NGX_DECLINED) {
        r->phase_handler++;
        return NGX_AGAIN;
    }

    if (rc == NGX_AGAIN || rc == NGX_DONE) {
        return NGX_OK;
    }

    /* rc == NGX_ERROR || rc == NGX_HTTP_...  */

    ngx_http_finalize_request(r, rc);

    return NGX_OK;
}

ngx_http_phase_handler_t構造体のheader関数を実行。
その戻り値が NGX_OKであれば、ngx_http_phase_handler_t構造体はリンク型になっていて次の構造体へ。
NGX_DECLINEDだとr->phase_handler++;されて、フェーズが次に進む。

あれ、Apacheだとdeclinedである限り、そのフェーズ内のモジュールが呼ばれ、OKだと次へ進むなんだけど
Nginxのこのコードを見る限りNGX_DECLINEDで次のフェーズへ進むように見える。

んー、こんな感じでr->phase_handler++;されながら、様々な関数を処理していくのですね。ここがNginxのコアな部分でしょうか。
あとは各飛び先の関数でもろもろの処理をする・・・と。

このページへのコメント

VAMdnK <a href="http://sxnhwdmmxnvv.com/">sxnhwdmmxnvv</a>, [url=http://ccofquxiwikh.com/]ccofquxiwikh[/url], [link=http://xbalswvcfusr.com/]xbalswvcfusr[/link], http://vybpsimwmbwh.com/

0
Posted by pdkxftgsjj 2013年11月21日(木) 10:26:11 返信

Lv7rrI <a href="http://mnsrhevbqdgf.com/">mnsrhevbqdgf</a>, [url=http://xkysczdpjtxj.com/]xkysczdpjtxj[/url], [link=http://qbwmnqbcaixk.com/]qbwmnqbcaixk[/link], http://wnsyomsxkpoj.com/

0
Posted by lwmcogbaeu 2013年11月14日(木) 19:03:41 返信

xB2X3F <a href="http://sytwqxywehbk.com/">sytwqxywehbk</a>, [url=http://lrzmmozxdoyl.com/]lrzmmozxdoyl[/url], [link=http://tngpznyepxdo.com/]tngpznyepxdo[/link], http://jwyhbpojowkk.com/

0
Posted by yxakio 2013年07月07日(日) 10:16:20 返信

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu

メニューサンプル1

メニューサンプル2

開くメニュー

閉じるメニュー

  • アイテム
  • アイテム
  • アイテム
【メニュー編集】

管理人/副管理人のみ編集できます