⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request.c

📁 用于移植到嵌入式linux系统的boa http服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifdef HAVE_SENDFILE                retval = io_shuffle_sendfile(current);#else                retval = io_shuffle(current);#endif                break;            case DONE:                /* a non-status that will terminate the request */                retval = req_flush(current);                /*                 * retval can be -2=error, -1=blocked, or bytes left                 */                if (retval == -2) { /* error */                    current->status = DEAD;                    retval = 0;                } else if (retval > 0) {                    retval = 1;                }                break;            case TIMED_OUT:            case DEAD:                retval = 0;                current->buffer_end = 0;                SQUASH_KA(current);                break;            default:                retval = 0;                fprintf(stderr, "Unknown status (%d), "                        "closing!\n", current->status);                current->status = DEAD;                break;            }        }        if (sigterm_flag)            SQUASH_KA(current);        /* we put this here instead of after the switch so that         * if we are on the last request, and get_request is successful,         * current->next is valid!         */        if (pending_requests)            get_request(server_sock);        switch (retval) {        case -1:               /* request blocked */            trailer = current;            current = current->next;            block_request(trailer);            break;        case 0:                /* request complete */            current->time_last = current_time;            trailer = current;            current = current->next;            free_request(trailer);            break;        case 1:                /* more to do */            current->time_last = current_time;            current = current->next;            break;        default:            log_error_doc(current);            fprintf(stderr, "Unknown retval in process.c - "                    "Status: %d, retval: %d\n", current->status, retval);            current->status = DEAD;            current = current->next;            break;        }    }}/* * Name: process_logline * * Description: This is called with the first req->header_line received * by a request, called "logline" because it is logged to a file. * It is parsed to determine request type and method, then passed to * translate_uri for further parsing.  Also sets up CGI environment if * needed. */int process_logline(request * req){    char *stop, *stop2;    req->logline = req->client_stream;    if (strlen(req->logline) < 5) {        /* minimum length req'd. */        log_error_doc(req);        fprintf(stderr, "Request too short: \"%s\"\n", req->logline);        send_r_bad_request(req);        return 0;    }    if (!memcmp(req->logline, "GET ", 4))        req->method = M_GET;    else if (!memcmp(req->logline, "HEAD ", 5))        /* head is just get w/no body */        req->method = M_HEAD;    else if (!memcmp(req->logline, "POST ", 5))        req->method = M_POST;    else {        log_error_doc(req);        fprintf(stderr, "malformed request: \"%s\"\n", req->logline);        send_r_not_implemented(req);        return 0;    }    req->http_version = HTTP10;    /* Guaranteed to find ' ' since we matched a method above */    stop = req->logline + 3;    if (*stop != ' ')        ++stop;    /* scan to start of non-whitespace */    while (*(++stop) == ' ');    stop2 = stop;    /* scan to end of non-whitespace */    while (*stop2 != '\0' && *stop2 != ' ')        ++stop2;    if (stop2 - stop > MAX_HEADER_LENGTH) {        log_error_doc(req);        fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,                req->logline);        send_r_bad_request(req);        return 0;    }    /* check for absolute URL */    if (!memcmp(stop, SERVER_METHOD,                strlen(SERVER_METHOD)) &&        !memcmp(stop + strlen(SERVER_METHOD), "://", 3)) {        char *host;        /* we have an absolute URL */        /* advance STOP until first '/' after host */        stop += strlen(SERVER_METHOD) + 3;        host = stop;        /* if *host is '/' there is no host in the URI         * if *host is ' ' there is corruption in the URI         * if *host is '\0' there is nothing after http://         */        if (*host == '/' || *host == ' ' || *host == '\0') {            /* nothing *at all* after http:// */            /* no host in absolute URI */            log_error_doc(req);            /* we don't need to log req->logline, because log_error_doc does */            fprintf(stderr, "bogus absolute URI\n");            send_r_bad_request(req);            return 0;        }        /* OK.  The 'host' is at least 1 char long.         * advance to '/', or end of host+url (' ' or ''\0')         */        while(*stop != '\0' && *stop != '/' && *stop != ' ')            ++stop;        if (*stop != '/') { /* *stop is '\0' or ' ' */            /* host is valid, but there is no URL. */            log_error_doc(req);            fprintf(stderr, "no URL in absolute URI: \"%s\"\n",                    req->logline);            send_r_bad_request(req);            return 0;        }        /* we have http://X/ where X is not ' ' or '/' (or '\0') */        /* since stop2 stops on '\0' and ' ', it *must* be after stop */        /* still, a safety check (belts and suspenders) */        if (stop2 < stop) {            /* Corruption in absolute URI */            /* This prevents a DoS attack from format string attacks */            log_error_doc(req);            fprintf(stderr, "Error: corruption in absolute URI:"                "\"%s\".  This should not happen.\n", req->logline);            send_r_bad_request(req);            return 0;        }        /* copy the URI */        memcpy(req->request_uri, stop, stop2 - stop);        /* place a NIL in the file spot to terminate host */        *stop = '\0';        /* place host */        /* according to RFC2616 --           1. If Request-URI is an absoluteURI, the host is part of the           Request-URI. Any Host header field value in the request MUST           be ignored.           Since we ignore any Host header if req->host is already set,           well, we rock!         */        req->header_host = host; /* this includes the port! (if any) */    } else {        /* copy the URI */        memcpy(req->request_uri, stop, stop2 - stop);    }    req->request_uri[stop2 - stop] = '\0';    /* METHOD URL\0 */    if (*stop2 == '\0')        req->http_version = HTTP09;    else if (*stop2 == ' ') {        /* if found, we should get an HTTP/x.x */        unsigned int p1, p2;        /* scan to end of whitespace */        ++stop2;        while (*stop2 == ' ' && *stop2 != '\0')            ++stop2;        if (*stop2 == '\0') {            req->http_version = HTTP09;        } else {            /* scan in HTTP/major.minor */            if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {                /* HTTP/{0.9,1.0,1.1} */                if (p1 == 0 && p2 == 9) {                    req->http_version = HTTP09;                } else if (p1 == 1 && p2 == 0) {                    req->http_version = HTTP10;                } else if (p1 == 1 && p2 == 1) {                    req->http_version = HTTP11;                    req->keepalive = KA_ACTIVE; /* enable keepalive */                    /* Disable send_r_continue because some clients                     * *still* don't work with it, Python 2.2 being one                     * see bug 227361 at the sourceforge web site.                     * fixed in revision 1.52 of httplib.py, dated                     * 2002-06-28 (perhaps Python 2.3 will                     * contain the fix.)                     *                     * Also, send_r_continue should *only* be                     * used if the expect header was sent.                     */                    /* send_r_continue(req); */                } else {                    goto BAD_VERSION;                }            } else {                goto BAD_VERSION;            }        }    }    if (req->method == M_HEAD && req->http_version == HTTP09) {        log_error("method is HEAD but version is HTTP/0.9");        send_r_bad_request(req);        return 0;    }    req->cgi_env_index = common_cgi_env_count;    return 1;  BAD_VERSION:    log_error_doc(req);    fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);    send_r_bad_request(req);    return 0;}/* * Name: process_header_end * * Description: takes a request and performs some final checking before * init_cgi or init_get * Returns 0 for error or NPH, or 1 for success */int process_header_end(request * req){    if (!req->logline) {        log_error_doc(req);        fputs("No logline in process_header_end\n", stderr);        send_r_error(req);        return 0;    }    /* Percent-decode request */    if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {        log_error_doc(req);        fputs("URI contains bogus characters\n", stderr);        send_r_bad_request(req);        return 0;    }    /* clean pathname */    clean_pathname(req->request_uri);    if (req->request_uri[0] != '/') {        log_error("URI does not begin with '/'\n");        send_r_bad_request(req);        return 0;    }    if (vhost_root) {        char *c;        if (!req->header_host) {            req->host = strdup(default_vhost);        } else {            req->host = strdup(req->header_host);        }        if (!req->host) {            log_error_doc(req);            fputs("unable to strdup default_vhost/req->header_host\n", stderr);            send_r_error(req);            return 0;        }        strlower(req->host);        /* check for port, and remove         * we essentially ignore the port, because we cannot         * as yet report a different port than the one we are         * listening on         */        c = strchr(req->host, ':');        if (c)            *c = '\0';        if (check_host(req->host) < 1) {            log_error_doc(req);            fputs("host invalid!\n", stderr);            send_r_bad_request(req);            return 0;        }    }    if (translate_uri(req) == 0) { /* unescape, parse uri */        /* errors already logged */        SQUASH_KA(req);        return 0;               /* failure, close down */    }    if (req->method == M_POST) {        req->post_data_fd = create_temporary_file(1, NULL, 0);        if (req->post_data_fd == 0) {            /* errors already logged */            send_r_error(req);            return 0;        }        if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) {            boa_perror(req, "unable to set close-on-exec for req->post_data_fd!");            close(req->post_data_fd);            req->post_data_fd = 0;            return 0;        }        return 1;             /* success */    }    if (req->cgi_type) {        return init_cgi(req);    }    req->status = WRITE;    return init_get(req);       /* get and head */}/* * Name: process_option_line * * Description: Parses the contents of req->header_line and takes * appropriate action. */int process_option_line(request * req){    char c, *value, *line = req->header_line;    /* Start by aggressively hacking the in-place copy of the header line */#ifdef FASCIST_LOGGING    log_error_time();    fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);#endif    value = strchr(line, ':');    if (value == NULL) {        log_error_doc(req);        fprintf(stderr, "header \"%s\" does not contain ':'\n", line);        return 0;    }    *value++ = '\0';            /* overwrite the : */    to_upper(line);             /* header types are case-insensitive */    /* the code below *does* catch '\0' due to the c = *value test */    while ((c = *value) && (c == ' ' || c == '\t'))        value++;    /* if c == '\0' there was no 'value' for the key */    if (c == '\0') {        /* return now to bypass any parsing or assignment */        return 1;    }    switch (line[0]) {    case 'A':        if (!memcmp(line, "ACCEPT", 7)) {#ifdef ACCEPT_ON            add_accept_header(req, value);#endif            return 1;        }        break;    case 'C':        if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) {            req->content_type = value;            return 1;        } else if (!memcmp(line, "CONTENT_LENGTH", 15)                   && !req->content_length) {            req->content_length = value;            return 1;        } else if (!memcmp(line, "CONNECTION", 11) &&                   ka_max && req->keepalive != KA_STOPPED) {            req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?                              KA_ACTIVE : KA_STOPPED);            return 1;        }        break;    case 'H':        if (!memcmp(line, "HOST", 5) && !req->header_host) {            req->header_host = value; /* may be complete garbage! */            return 1;        }        break;    case 'I':        if (!memcmp(line, "IF_MODIFIED_SINCE", 18)            && !req->if_modified_since) {            req->if_modified_since = value;            return 1;        }        break;    case 'R':        /* Need agent and referer for logs */        if (!memcmp(line, "REFERER", 8)) {            req->header_referer = value;            if (!add_cgi_env(req, "REFERER", value, 1)) {                /* errors already logged */                return 0;            }        } else if (!memcmp(line, "RANGE", 6)) {            if (req->ranges && req->ranges->stop == INT_MAX) {                /* there was an error parsing, ignore */                return 1;            } else if (!range_parse(req, value)) {                /* unable to parse range */                send_r_invalid_range(req);                return 0;            }                   /* req->ranges */        }        break;    case 'U':        if (!memcmp(line, "USER_AGENT", 11)) {            req->header_user_agent = value;            if (!add_cgi_env(req, "USER_AGENT", value, 1)) {                /* errors already logged */                return 0;            }            return 1;        }        break;    default:                   /* no default */        break;    }                           /* switch */    return add_cgi_env(req, line, value, 1);}#ifdef ACCEPT_ON/* * Name: add_accept_header * Description: Adds a mime_type to a requests accept char buffer *   silently ignore any that don't fit - *   shouldn't happen because of relative buffer sizes */void add_accept_header(request * req, const char *mime_type){    int l = strlen(req->accept);    int l2 = strlen(mime_type);    if ((l + l2 + 2) >= MAX_HEADER_LENGTH)        return;    if (req->accept[0] == '\0') {        memcpy(req->accept, mime_type, l2 + 1);    } else {        req->accept[l] = ',';        req->accept[l + 1] = ' ';        memcpy(req->accept + l + 2, mime_type, l2 + 1);        /* the +1 is for the '\0' */    }}#endifvoid free_requests(void) {    request *ptr, *next;    ptr = request_free;    while (ptr != NULL) {        next = ptr->next;        free(ptr);        ptr = next;    }    request_free = NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -