nginx源碼分析——http處理流程

1. http處理流程概述

nginx對於http請求處理的大概流程是:接收客戶端發起的鏈接,而後接收並解析http請求行,接收並解析http頭部;再根據配置文件nginx.conf找到相關http模塊,使這些模塊依次合做處理http請求,最後發送http響應並結束http請求。nginx

在整個http請求處理過程當中,nginx經過鏈接的讀寫事件,以及定時器機制,異步回調完成其處理流程。異步

2. http新鏈接的創建

事件模塊一文中咱們知道,當新鏈接創建後會回調對應偵聽的處理方法。對於http模塊,該回調方法爲ngx_http_init_connection。在該方法中,主要完成的事情是:設置鏈接的讀事件回調處理方法爲ngx_http_wait_request_handler,設置鏈接的寫事件回調處理方法爲ngx_http_empty_handler;而後查看讀事件是否已經準備好,即鏈接對應的套接字緩衝區上是否已經接收到用戶的請求數據了,若是是,則直接調用ngx_http_wait_request_handler進入下一處理步驟;若是尚未準備好,則對鏈接的讀事件設置定時器,同時將讀事件添加到事件驅動中,等待下一次回調處理。函數

void ngx_http_init_connection(ngx_connection_t *c)
{
    ...
    // 設置讀寫事件回調處理方法
    rev = c->read;
    rev->handler = ngx_http_wait_request_handler;
    c->write->handler = ngx_http_empty_handler;

    if( rev->ready ) {
        if( ngx_use_accept_mutex ) {
            ngx_post_event(rev, &ngx_posted_events);
            return;
        }
        // 事件已經準備好, 直接處理
        rev->handler(rev);
        return;
    }

    // 設置定時器
    ngx_add_timer(rev, c->listening->post_accept_timeout);
    ngx_reusable_connection(c, 1);

    // 將讀事件加入事件驅動中
    if(ngx_handle_read_event(rev, 0) != NGX_OK) {
        ngx_http_close_connection(c);
        return;
    }
}

3. 首次可讀事件的處理

當鏈接對應的套接字緩衝區首次接收到用戶的請求數據後,會回調ngx_http_wait_request_handler方法,在該函數中,會調用recv接收用戶的請求數據,同時建立一個ngx_http_request_t用於本次http請求處理,而後調用ngx_http_process_request_line開始處理http請求行。post

static void ngx_http_wait_request_handler(ngx_event_t *rev)
{
    ....
    // 接收數據
    n = c->recv(c, b->last, size);
    if( n == NGX_AGAIN ) {
        if(!rev->timer_set) {
            ngx_add_timer(rev, c->listening->post_accept_timeout);
            ngx_reusable_connection(c, 1);
        }
        if( ngx_handle_read_event(rev,0) != NGX_OK ) {
            ngx_http_close_connection(c);
            return ;
        }
    }
    if(n == NGX_ERROR ) {
        ngx_http_close_connection(c);
        return ;
    }

    ....
    
    // 建立request
    c->data = ngx_http_create_request(c);
    if(c->data == NULL) {
        ngx_http_close_connection(c);
        return ;
    }
    rev->handler = ngx_http_process_request_line;
    ngx_http_post_request_line(rev);
}

4. http請求行/http頭部的接收處理

在完成了請求的初始化後,會依次調用ngx_http_process_request_line和ngx_http_process_request_headers方法開始接收http請求行和http頭部,並解析出URL,請求方法等各字段的含義。當這些都處理完成後,調用ngx_http_process_request進入請求真正的處理階段。spa

static void ngx_http_process_request_line(ngx_event_t * rev)
{
    ....
    for( ;; ) {
        // 解析 http行
        rc = ngx_http_parse_request_line(r, r->header_in);
        if( rc == NGX_OK ) {
            // 處理http uri
            if(ngx_http_process_request_uri(r) != NGX_OK) {
                return ;
            }

            // 設置鏈接的讀事件回調處理, 並開始處理http請求的頭部
            rev->handler = ngx_http_process_request_headers;
            ngx_http_process_request_headers(rev);
            return ;
        }
    }
}

static void ngx_http_process_request_headers(ngx_event_t * rev)
{
    ....
    rc = NGX_AGAIN;
    for( ;; ) {
        if( rc == NGX_AGAIN ) {
            n = ngx_http_request_header(r);
        }

        // 解析http的頭部
        rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers);
        if( rc == NGX_HTTP_PARSE_HEADER_DONE) {
            r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
            // 處理http的頭部
            rc = ngx_http_process_request_header(r);
            if(rc != NGX_OK) {
                return ;
            }
            // 開始http請求的處理
            ngx_http_process_request(r);
            return ;
        }
    }
}

5. http請求的處理

在ngx_http_process_request中,將鏈接讀寫事件的回調處理均設置爲ngx_http_request_handler方法,而後調用ngx_http_handler,而在ngx_http_handler中最終調用ngx_http_core_run_phases開始http的多階段處理。.net

void ngx_http_process_request(ngx_http_request_t *r )
{
    ....
    c->read->handler = ngx_http_request_handler;
    c->write->handler = ngx_http_request_handler;
    c->read_event_handler = ngx_http_block_reading;
    ngx_http_handler(r);
    ngx_http_run_posted_requests(c);
}

void ngx_http_handler(ngx_http_request_t * r)
{
    ...
    // 開始http請求的多階段處理
    r->write_event_handler = ngx_http_core_run_phases;
    ngx_http_core_run_phases(r);
}

6. 發送http請求響應

http請求響應回覆通常會經過ngx_http_send_header發送http頭部,經過ngx_http_output_filter發送http的包體。ngx_http_send_header和ngx_http_output_filter都是由一系列的filter模塊組成,這些模塊對響應數據進行加工處理,最終調用ngx_http_write_filter進行數據的發送。code

ngx_int_t ngx_http_send_header(ngx_http_request_t *r)
{
    ....
    return ngx_http_top_header_filter(r);
}

ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ....
    rc = ngx_http_top_body_filter(r, in);
    ....
}

7. 結束http請求

通常來說,結束http請求會調用ngx_http_finalize_request來完成。到這裏,整個http的處理流程結束。blog

相關文章
相關標籤/搜索