FreeSWITCH - mod_xml_rpc源碼分析九session.c


_TSession

struct _TSession {
    bool validRequest;
        /* Client has sent, and server has recognized, a valid HTTP request.
           This is false when the session is new.  If and when the server
           reads the request from the client and finds it to be valid HTTP,
           it becomes true.
        */
    TRequestInfo requestInfo;
        /* Some of the strings this references are in individually malloc'ed
           memory, but some are pointers into arbitrary other data structures
           that happen to live as long as the session.  Some day, we will
           fix that.

           'requestInfo' is valid only if 'validRequest' is true.
        */
    uint32_t nbfileds;
    TList cookies;
    TList ranges;

    uint16_t status;
        /* Response status from handler.  Zero means session is not ready
           for a response yet.  This can mean that we ran a handler and it
           did not call ResponseStatus() to declare this fact.
        */
    TString header;

    bool serverDeniesKeepalive;
        /* Server doesn't want keepalive for this session, regardless of
           what happens in the session.  E.g. because the connection has
           already been kept alive long enough.
        */
    bool responseStarted;
        /* Handler has at least started the response (i.e. called
           ResponseWriteStart())
        */

    struct _TConn * conn;

    httpVersion version;

    TTable request_headers;
        /* All the headers in the HTTP request.  The key is the header
           name in lower case.  The value is the verbatim value from
           the header.
        */

    TTable response_headers;

    time_t date;

    bool chunkedwrite;
    bool chunkedwritemode;

    bool continueRequired;
        /* This client must receive 100 (continue) status before it will
           send more of the body of the request.
        */
};

之前在研究server.c文件內的processDataFromClient函數時第一次看到了TSession。由於每次收到一個數據包後都會調用processDataFromClient函數,所以我認爲TSession是對一個請求的封裝。大致瀏覽了下_TSession結構體的聲明後,我覺得更應該是針對某個HTTP請求數據報文的封裝。

typedef struct {
    TMethod method;
    const char * uri;
        /* This is NOT the URI.  It is the pathname part of the URI.
           We really should fix that and put the pathname in another
           member.  If the URI does not contain a pathname, this is "*".
        */
    const char * query;
        /* The query part of the URI (stuff after '?').  NULL if none. */
    const char * host;
        /* NOT the value of the host: header.  Rather, the name of the
           target host (could be part of the host: value; could be from the
           URI).  No port number.  NULL if request does not specify a host
           name.
        */
    const char * from;
    const char * useragent;
    const char * referer;
    const char * requestline;
    const char * user;
        /* Requesting user (from authorization: header).  NULL if
           request doesn't specify or handler has not authenticated it.
        */
    xmlrpc_uint16_t port;
        /* The port number from the URI, or default 80 if the URI doesn't
           specify a port.
        */
    abyss_bool keepalive;
} TRequestInfo;
TRequestInfo結構體內有method方法(應該是HTTP Method,類似於GET、POST等)、uri、query、host(主機)、port(端口號)和useragent等信息。這些都是一個HTTP請求所必需包含的信息。_TSession還包括cookies和request_headers等數據。這些數據都表明_TSession是針對一個HTTP請求數據報文的封裝。


初始化

簡單過了一遍session.c文件,沒有看到所謂的初始化函數。之前研究processDataFromClient函數時看到過RequestInit函數,但這個函數是在http.c文件中。個人覺得這個函數還是放在session.c文件中比較好,最起碼從概念上說與session.c文件中的其他函數比較接近。


這個文件內的有一些函數基本上屬於輔助函數,有點類似於面嚮對象語言裏的GET函數。例如,SessionGetRequestInfo、SessionGetChannelInfo和SessionGetDefaultHandlerCtx。SessionLog函數的作用是將_TSession的一些主要屬性信息輸出至日誌。


SessionGetReadyData

依據函數頭部的註釋可以獲知此函數的用途是返回HTTP請求的body域內容。


SessionReadDataAvail

此函數的作用是檢查緩存區內是否還有剩餘未處理的數據。


SessionRefillBuffer

abyss_bool
SessionRefillBuffer(TSession * const sessionP) {
/*----------------------------------------------------------------------------
   Get the next chunk of HTTP request body from the connection into
   the buffer.

   I.e. read data from the socket.
-----------------------------------------------------------------------------*/
    struct _TServer * const srvP = sessionP->conn->server->srvP;
    bool failed;

    failed = FALSE;  /* initial value */
            
    /* Reset our read buffer & flush data from previous reads. */
    ConnReadInit(sessionP->conn);

    if (sessionP->continueRequired)
        failed = !HTTPWriteContinue(sessionP);

    if (!failed) {
        sessionP->continueRequired = FALSE;

        /* Read more network data into our buffer.  If we encounter a
           timeout, exit immediately.  We're very forgiving about the
           timeout here.  We allow a full timeout per network read, which
           would allow somebody to keep a connection alive nearly
           indefinitely.  But it's hard to do anything intelligent here
           without very complicated code.
        */
        failed = !ConnRead(sessionP->conn, srvP->timeout);	
    }
    return !failed;
}
函數頭部的註釋說明了這個函數的用途:從連接中讀取HTTP請求中下一個數據塊,並放入緩存區中。首先使用ConnReadInit函數重置內部接收數據緩存區。接着調用HTTPWriteContinue函數檢查此連接是否還可以繼續使用。最後會調用ConnRead函數進行實際的收取網絡數據的操作。

bool
HTTPWriteContinue(TSession * const sessionP) {

    char const continueStatus[] = "HTTP/1.1 100 continue\r\n\r\n";
        /* This is a status line plus an end-of-headers empty line */

    return ConnWrite(sessionP->conn, continueStatus, strlen(continueStatus));
}
HTTPWriteContineu函數體顯示它只是發送了一條HTTP消息給對端。也就是說,這個函數的用途不是用來監測連接是否還可以繼續使用,而應該是通知對端請繼續發送數據。如果這條消息發送成功了,說明連接還存在,因此可以繼續調用ConnRead函數從連接中讀取數據。

因此SessionRefillBuffer函數的用途是在某種情況下希望對方能繼續將一個完整HTTP請求數據包發送完畢。










發佈了82 篇原創文章 · 獲贊 2 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章