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

📄 mod_isapi.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
         * lock so other requests can proceed, then rdlock for completion
         * of loading our desired dll or wrlock if we would like to retry
         * loading the dll (because last_load_rv failed and retry is up.)
         */
        apr_thread_rwlock_t *gainlock = (*isa)->in_progress;

        /* gainlock is NULLed after the module loads successfully.
         * This free-threaded module can be used without any locking.
         */
        if (!gainlock) {
            rv = (*isa)->last_load_rv;
            apr_thread_mutex_unlock(loaded.lock);
            return rv;
        }


        if ((*isa)->last_load_rv == APR_SUCCESS) {
            apr_thread_mutex_unlock(loaded.lock);
            if ((rv = apr_thread_rwlock_rdlock(gainlock))
                    != APR_SUCCESS) {
                return rv;
            }
            rv = (*isa)->last_load_rv;
            apr_thread_rwlock_unlock(gainlock);
            return rv;
        }

        if (apr_time_now() > (*isa)->last_load_time + ISAPI_RETRY) {

            /* Remember last_load_time before releasing the global
             * hash lock to avoid colliding with another thread
             * that hit this exception at the same time as our
             * retry attempt, since we unlock the global mutex
             * before attempting a write lock for this module.
             */
            apr_time_t check_time = (*isa)->last_load_time;
            apr_thread_mutex_unlock(loaded.lock);

            if ((rv = apr_thread_rwlock_wrlock(gainlock))
                    != APR_SUCCESS) {
                return rv;
            }

            /* If last_load_time is unchanged, we still own this
             * retry, otherwise presume another thread provided
             * our retry (for good or ill).  Relock the global
             * hash for updating last_load_ vars, so their update
             * is always atomic to the global lock.
             */
            if (check_time == (*isa)->last_load_time) {

                rv = isapi_load(loaded.pool, s, *isa);

                apr_thread_mutex_lock(loaded.lock);
                (*isa)->last_load_rv = rv;
                (*isa)->last_load_time = apr_time_now();
                apr_thread_mutex_unlock(loaded.lock);
            }
            else {
                rv = (*isa)->last_load_rv;
            }
            apr_thread_rwlock_unlock(gainlock);

            return rv;
        }

        /* We haven't hit timeup on retry, let's grab the last_rv
         * within the hash mutex before unlocking.
         */
        rv = (*isa)->last_load_rv;
        apr_thread_mutex_unlock(loaded.lock);

        return rv;
    }

    /* If the module was not found, it's time to create a hash key entry
     * before releasing the hash lock to avoid multiple threads from
     * loading the same module.
     */
    key = apr_pstrdup(loaded.pool, fpath);
    *isa = apr_pcalloc(loaded.pool, sizeof(isapi_loaded));
    (*isa)->filename = key;
    if (r) {
        /* A mutex that exists only long enough to attempt to
         * load this isapi dll, the release this module to all
         * other takers that came along during the one-time
         * load process.  Short lifetime for this lock would
         * be great, however, using r->pool is nasty if those
         * blocked on the lock haven't all unlocked before we
         * attempt to destroy.  A nastier race condition than
         * I want to deal with at this moment...
         */
        apr_thread_rwlock_create(&(*isa)->in_progress, loaded.pool);
        apr_thread_rwlock_wrlock((*isa)->in_progress);
    }

    apr_hash_set(loaded.hash, key, APR_HASH_KEY_STRING, *isa);

    /* Now attempt to load the isapi on our own time,
     * allow other isapi processing to resume.
     */
    apr_thread_mutex_unlock(loaded.lock);

    rv = isapi_load(loaded.pool, s, *isa);
    (*isa)->last_load_time = apr_time_now();
    (*isa)->last_load_rv = rv;

    if (r && (rv == APR_SUCCESS)) {
        /* Let others who are blocked on this particular
         * module resume their requests, for better or worse.
         */
        apr_thread_rwlock_t *unlock = (*isa)->in_progress;
        (*isa)->in_progress = NULL;
        apr_thread_rwlock_unlock(unlock);
    }
    else if (!r && (rv != APR_SUCCESS)) {
        /* We must leave a rwlock around for requests to retry
         * loading this dll after timeup... since we were in
         * the setup code we had avoided creating this lock.
         */
        apr_thread_rwlock_create(&(*isa)->in_progress, loaded.pool);
    }

    return (*isa)->last_load_rv;
}

/**********************************************************
 *
 *  ISAPI Module request callbacks section
 *
 **********************************************************/

/* Our "Connection ID" structure */
struct isapi_cid {
    EXTENSION_CONTROL_BLOCK *ecb;
    isapi_dir_conf           dconf;
    isapi_loaded            *isa;
    request_rec             *r;
    int                      headers_set;
    int                      response_sent;
    PFN_HSE_IO_COMPLETION    completion;
    void                    *completion_arg;
    apr_thread_mutex_t      *completed;
};

int APR_THREAD_FUNC GetServerVariable (isapi_cid    *cid,
                                       char         *variable_name,
                                       void         *buf_ptr,
                                       apr_uint32_t *buf_size)
{
    request_rec *r = cid->r;
    const char *result;
    char *buf_data = (char*)buf_ptr;
    apr_uint32_t len;

    if (!strcmp(variable_name, "ALL_HTTP"))
    {
        /* crlf delimited, colon split, comma separated and
         * null terminated list of HTTP_ vars
         */
        const apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
        const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
        int i;

        for (len = 0, i = 0; i < arr->nelts; i++) {
            if (!strncmp(elts[i].key, "HTTP_", 5)) {
                len += strlen(elts[i].key) + strlen(elts[i].val) + 3;
            }
        }

        if (*buf_size < len + 1) {
            *buf_size = len + 1;
            apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER));
            return 0;
        }

        for (i = 0; i < arr->nelts; i++) {
            if (!strncmp(elts[i].key, "HTTP_", 5)) {
                strcpy(buf_data, elts[i].key);
                buf_data += strlen(elts[i].key);
                *(buf_data++) = ':';
                strcpy(buf_data, elts[i].val);
                buf_data += strlen(elts[i].val);
                *(buf_data++) = '\r';
                *(buf_data++) = '\n';
            }
        }

        *(buf_data++) = '\0';
        *buf_size = len + 1;
        return 1;
    }

    if (!strcmp(variable_name, "ALL_RAW"))
    {
        /* crlf delimited, colon split, comma separated and
         * null terminated list of the raw request header
         */
        const apr_array_header_t *arr = apr_table_elts(r->headers_in);
        const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
        int i;

        for (len = 0, i = 0; i < arr->nelts; i++) {
            len += strlen(elts[i].key) + strlen(elts[i].val) + 4;
        }

        if (*buf_size < len + 1) {
            *buf_size = len + 1;
            apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER));
            return 0;
        }

        for (i = 0; i < arr->nelts; i++) {
            strcpy(buf_data, elts[i].key);
            buf_data += strlen(elts[i].key);
            *(buf_data++) = ':';
            *(buf_data++) = ' ';
            strcpy(buf_data, elts[i].val);
            buf_data += strlen(elts[i].val);
            *(buf_data++) = '\r';
            *(buf_data++) = '\n';
        }
        *(buf_data++) = '\0';
        *buf_size = len + 1;
        return 1;
    }

    /* Not a special case */
    result = apr_table_get(r->subprocess_env, variable_name);

    if (result) {
        len = strlen(result);
        if (*buf_size < len + 1) {
            *buf_size = len + 1;
            apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER));
            return 0;
        }
        strcpy(buf_data, result);
        *buf_size = len + 1;
        return 1;
    }

    /* Not Found */
    apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_INDEX));
    return 0;
}

int APR_THREAD_FUNC ReadClient(isapi_cid    *cid,
                               void         *buf_data,
                               apr_uint32_t *buf_size)
{
    request_rec *r = cid->r;
    apr_uint32_t read = 0;
    int res;

    if (r->remaining < *buf_size) {
        *buf_size = (apr_size_t)r->remaining;
    }

    while (read < *buf_size &&
           ((res = ap_get_client_block(r, (char*)buf_data + read,
                                       *buf_size - read)) > 0)) {
        read += res;
    }

    *buf_size = read;
    if (res < 0) {
        apr_set_os_error(APR_FROM_OS_ERROR(ERROR_READ_FAULT));
    }
    return (res >= 0);
}

/* Common code invoked for both HSE_REQ_SEND_RESPONSE_HEADER and
 * the newer HSE_REQ_SEND_RESPONSE_HEADER_EX ServerSupportFunction(s)
 * as well as other functions that write responses and presume that
 * the support functions above are optional.
 *
 * Other callers trying to split headers and body bytes should pass
 * head/headlen alone (leaving stat/statlen NULL/0), so that they
 * get a proper count of bytes consumed.  The argument passed to stat
 * isn't counted as the head bytes are.
 */
static apr_ssize_t send_response_header(isapi_cid *cid,
                                        const char *stat,
                                        const char *head,
                                        apr_size_t statlen,
                                        apr_size_t headlen)
{
    int head_present = 1;
    int termarg;
    int res;
    int old_status;
    const char *termch;
    apr_size_t ate = 0;

    if (!head || headlen == 0 || !*head) {
        head = stat;
        stat = NULL;
        headlen = statlen;
        statlen = 0;
        head_present = 0; /* Don't eat the header */
    }

    if (!stat || statlen == 0 || !*stat) {
        if (head && headlen && *head && ((stat = memchr(head, '\r', headlen))
                                      || (stat = memchr(head, '\n', headlen))
                                      || (stat = memchr(head, '\0', headlen))
                                      || (stat = head + headlen))) {
            statlen = stat - head;
            if (memchr(head, ':', statlen)) {
                stat = "Status: 200 OK";
                statlen = strlen(stat);
            }
            else {
                const char *flip = head;
                head = stat;
                stat = flip;
                headlen -= statlen;
                ate += statlen;
                if (*head == '\r' && headlen)
                    ++head, --headlen, ++ate;
                if (*head == '\n' && headlen)
                    ++head, --headlen, ++ate;
            }
        }
    }

    if (stat && (statlen > 0) && *stat) {
        char *newstat;
        if (!apr_isdigit(*stat)) {
            const char *stattok = stat;
            int toklen = statlen;
            while (toklen && *stattok && !apr_isspace(*stattok)) {
                ++stattok; --toklen;
            }
            while (toklen && apr_isspace(*stattok)) {
                ++stattok; --toklen;
            }
            /* Now decide if we follow the xxx message
             * or the http/x.x xxx message format
             */
            if (toklen && apr_isdigit(*stattok)) {

⌨️ 快捷键说明

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