BOA read_header 分析


隨意抓的一個HTTP包,以做參考

wKioL1NmOpjRvRZAAAIovk5YvXM931.jpg

代碼分析:

int read_header(request * req)
{
    int bytes, buf_bytes_left;
    char *check, *buffer;
    /*
    client_stream:是用來裝HTTP數據報文的buffer。
    parse_pos:已經解析字符數。
    client_stream_pos:從socket中讀取的字符數。
    */
    check = req->client_stream + req->parse_pos;
    buffer = req->client_stream;
    bytes = req->client_stream_pos;
#ifdef VERY_FASCIST_LOGGING
    if (check < (buffer + bytes)) {
        buffer[bytes] = '\0';
        log_error_time();
        fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n",
                __FILE__, __LINE__, check);
    }
#endif
    while (check < (buffer + bytes)) {
        switch (req->status) {
        case READ_HEADER:
            if (*check == '\r') {
                req->status = ONE_CR;
                req->header_end = check;
            } else if (*check == '\n') {
                req->status = ONE_LF;
                req->header_end = check;
            }
            break;
/*  HTTP數據包,每條信息結尾都以\r\n結尾,
    但一些較老的客戶端可能仍然用\n結尾,
    所以我們的WEB服務器一般都有一定的容錯能力,
    當直接檢測到結尾是\n時,直接跳到ONE_LF狀態,
    絲毫不影響對HTTP包頭的解析。*/
        case ONE_CR:
            if (*check == '\n')
                req->status = ONE_LF;
            else if (*check != '\r')
                req->status = READ_HEADER;
            break;
        case ONE_LF:
            /* if here, we've found the end (for sure) of a header */
            if (*check == '\r') /* could be end o headers */
                req->status = TWO_CR;
            else if (*check == '\n')
                req->status = BODY_READ;
            else
                req->status = READ_HEADER;
            break;
/*HTTP 以單獨的一行\r\n 結尾所以當連續出現\r\n 時說明HTTP頭解析完成*/
        case TWO_CR:
            if (*check == '\n')
                req->status = BODY_READ;
            else if (*check != '\r')
                req->status = READ_HEADER;
            break;
        default:
            break;
        }
#ifdef VERY_FASCIST_LOGGING
        log_error_time();
        fprintf(stderr, "status, check: %d, %d\n", req->status, *check);
#endif
        req->parse_pos++;       /* update parse position */
        check++;
        if (req->status == ONE_LF) {
            *req->header_end = '\0';
            /* terminate string that begins at req->header_line */
            if (req->logline) {
                if (process_option_line(req) == 0) {//解析HTTP頭部信息並放入結構體內
                    return 0;
                }
            } else {
                if (process_logline(req) == 0)//解析HTTP 頭的第一行,確定訪問方式GET POST HEAD
                    return 0;
                if (req->simple)
                    return process_header_end(req);
            }
            /* set header_line to point to beginning of new header */
            req->header_line = check;
        } else if (req->status == BODY_READ) {//處理HTTP 主體部分
#ifdef VERY_FASCIST_LOGGING
            int retval;
            log_error_time();
            fprintf(stderr, "%s:%d -- got to body read.\n",
                    __FILE__, __LINE__);
            retval = process_header_end(req);
#else
            int retval = process_header_end(req);////調用CGI之前做最後的處理
#endif
            /* process_header_end inits non-POST cgi's */
            if (retval && req->method == M_POST) {
                /* for body_{read,write}, set header_line to start of data,
                   and header_end to end of data */
                req->header_line = check;
                req->header_end =
                    req->client_stream + req->client_stream_pos;
                req->status = BODY_WRITE;
                /* so write it */
                /* have to write first, or read will be confused
                 * because of the special case where the
                 * filesize is less than we have already read.
                 */
                /*
                   As quoted from RFC1945:
                   A valid Content-Length is required on all HTTP/1.0 POST requests. An
                   HTTP/1.0 server should respond with a 400 (bad request) message if it
                   cannot determine the length of the request message's content.
                 */
                if (req->content_length) {
                    int content_length;
                    content_length = boa_atoi(req->content_length);
                    /* Is a content-length of 0 legal? */
                    if (content_length <= 0) {
                        log_error_time();
                        fprintf(stderr, "Invalid Content-Length [%s] on POST!\n",
                                req->content_length);
                        send_r_bad_request(req);
                        return 0;
                    }
                    if (single_post_limit && content_length > single_post_limit) {
                        log_error_time();
                        fprintf(stderr, "Content-Length [%d] > SinglePostLimit [%d] on POST!\n",
                                content_length, single_post_limit);
                        send_r_bad_request(req);
                        return 0;
                    }
                    req->filesize = content_length;
                    req->filepos = 0;
                    if (req->header_end - req->header_line > req->filesize) {
                        req->header_end = req->header_line + req->filesize;
                    }
                } else {
                    log_error_time();
                    fprintf(stderr, "Unknown Content-Length POST!\n");
                    send_r_bad_request(req);
                    return 0;
                }
            }                   /* either process_header_end failed or req->method != POST */
            return retval;      /* 0 - close it done, 1 - keep on ready */
        }                       /* req->status == BODY_READ */
    }                           /* done processing available buffer */
#ifdef VERY_FASCIST_LOGGING
    log_error_time();
    fprintf(stderr, "%s:%d - Done processing buffer.  Status: %d\n",
            __FILE__, __LINE__, req->status);
#endif
/*  在分析主體部分之前,
    也就是在分析HTTP所承載的數據之前不斷的從socket中讀取HTTP頭數據進行解析。*/
    if (req->status < BODY_READ) {
        /* only reached if request is split across more than one packet */
        buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos;
        if (buf_bytes_left < 1) {
            log_error_time();
            fputs("buffer overrun - read.c, read_header - closing\n",
                  stderr);
            req->status = DEAD;
            return 0;
        }
        bytes = read(req->fd, buffer + req->client_stream_pos, buf_bytes_left);
        if (bytes < 0) {
            if (errno == EINTR)
                return 1;
            if (errno == EAGAIN || errno == EWOULDBLOCK) /* request blocked */
                return -1;
            /*
               else if (errno == EBADF || errno == EPIPE) {
               req->status = DEAD;
               return 0;
               */
            log_error_doc(req);
            perror("header read");            /* don't need to save errno because log_error_doc does */
            return 0;
        } else if (bytes == 0) {
            /*
               log_error_time();
               fputs("unexpected end of headers\n", stderr);
             */
            return 0;
        }
        /* bytes is positive */
        req->client_stream_pos += bytes;
#ifdef FASCIST_LOGGING1
        log_error_time();
        req->client_stream[req->client_stream_pos] = '\0';
        fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n",
                __FILE__, __LINE__, bytes,
#ifdef VERY_FASCIST_LOGGING2
                req->client_stream + req->client_stream_pos - bytes);
#else
                "");
#endif
#endif
        return 1;
    }
    return 1;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章