static int init_ws_service()

in native/iis/jk_isapi_plugin.c [3072:3455]


static int init_ws_service(isapi_private_data_t * private_data,
                           jk_ws_service_t *s, char **worker_name)
{
    char *all_headers;
    int worker_index = -1;
    rule_extension_t *e;
    char  temp_buf[64];
    BOOL  unknown_content_length = FALSE;
    unsigned int cnt = 0;
    char *tmp;
    jk_log_context_t *l = s->log_ctx;

    JK_TRACE_ENTER(l);

    s->start_response = start_response;
    s->read  = iis_read;
    s->write = iis_write;
    s->done  = iis_done;

    l = jk_pool_alloc(s->pool, sizeof(jk_log_context_t));
    l->logger = logger;
    l->id = "INIT_WS_SERVICE";
    GET_SERVER_VARIABLE_VALUE(HTTP_REQUEST_ID_HEADER_NAME, l->id, "NO-ID");
    s->log_ctx = l;

    GET_SERVER_VARIABLE_VALUE(HTTP_URI_HEADER_NAME, s->req_uri, NULL);

    if (s->req_uri == NULL) {
        if (JK_IS_DEBUG_LEVEL(l))
            jk_log(l, JK_LOG_DEBUG, "No URI header value provided. Defaulting to old behaviour");
        s->query_string = private_data->lpEcb->lpszQueryString;
        *worker_name = DEFAULT_WORKER_NAME;
        GET_SERVER_VARIABLE_VALUE("URL", s->req_uri, "");
        if (unescape_url(s->req_uri) < 0) {
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }
        jk_servlet_normalize(s->req_uri, l);
    }
    else {
        GET_SERVER_VARIABLE_VALUE(HTTP_QUERY_HEADER_NAME, s->query_string, "");
        GET_SERVER_VARIABLE_VALUE(HTTP_WORKER_HEADER_NAME, (*worker_name), "");
        GET_SERVER_VARIABLE_VALUE_INT(HTTP_WORKER_HEADER_INDEX, worker_index, -1);
    }

    if (JK_IS_DEBUG_LEVEL(l)) {
        jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_WORKER_HEADER_NAME, (*worker_name));
        jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %d", HTTP_WORKER_HEADER_INDEX, worker_index);
        jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_URI_HEADER_NAME, s->req_uri);
        jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_QUERY_HEADER_NAME, s->query_string);
        jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_REQUEST_ID_HEADER_NAME, s->log_ctx->id);
    }

    GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type, NULL);
    GET_SERVER_VARIABLE_VALUE("REMOTE_USER", s->remote_user, NULL);
    GET_SERVER_VARIABLE_VALUE("SERVER_PROTOCOL", s->protocol, "");
    GET_SERVER_VARIABLE_VALUE("REMOTE_HOST", s->remote_host, "");
    GET_SERVER_VARIABLE_VALUE("REMOTE_ADDR", s->remote_addr, "");
    GET_SERVER_VARIABLE_VALUE("REMOTE_PORT", s->remote_port, "");
    GET_SERVER_VARIABLE_VALUE("SERVER_NAME", s->server_name, "");
    GET_SERVER_VARIABLE_VALUE("LOCAL_ADDR", s->local_addr, "");
    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT", s->server_port, 80);
    GET_SERVER_VARIABLE_VALUE("SERVER_SOFTWARE", s->server_software, "");
    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT_SECURE", s->is_ssl, 0);

    s->method = private_data->lpEcb->lpszMethod;
    /* Check for Transfer Encoding */
    if (get_server_value(private_data->lpEcb,
                         "HTTP_TRANSFER_ENCODING",
                         temp_buf,
                         sizeof(temp_buf))) {
        if (strcasecmp(temp_buf, TRANSFER_ENCODING_CHUNKED_VALUE) == 0) {
            s->is_chunked = JK_TRUE;
            if (JK_IS_DEBUG_LEVEL(l)) {
                jk_log(l, JK_LOG_DEBUG, "Request is Transfer-Encoding: chunked");
            }
        }
        else {
            /* XXX: What to do with non chunked T-E ?
             */
            if (JK_IS_DEBUG_LEVEL(l))
                jk_log(l, JK_LOG_DEBUG, "Unsupported Transfer-Encoding: %s",
                       temp_buf);
        }
    }
    if (private_data->lpEcb->cbTotalBytes == 0xFFFFFFFF) {
        /* We have size larger then 4Gb or Transfer-Encoding: chunked
         * ReadClient should be called until no more data is returned
         */
        unknown_content_length = TRUE;
    }
    else {
        /* Use the IIS provided content length */
        s->content_length = (jk_uint64_t)private_data->lpEcb->cbTotalBytes;
    }
    e = get_uri_to_worker_ext(uw_map, worker_index);
    if (e) {
        if (JK_IS_DEBUG_LEVEL(l))
            jk_log(l, JK_LOG_DEBUG, "Applying service extensions");
        s->extension.reply_timeout = e->reply_timeout;
        s->extension.sticky_ignore = e->sticky_ignore;
        s->extension.stateless = e->stateless;
        s->extension.use_server_error_pages = e->use_server_error_pages;
        if (e->activation) {
            s->extension.activation = jk_pool_alloc(s->pool, e->activation_size * sizeof(int));
            memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
        }
        if (e->fail_on_status_size > 0) {
            s->extension.fail_on_status_size = e->fail_on_status_size;
            s->extension.fail_on_status = jk_pool_alloc(s->pool, e->fail_on_status_size * sizeof(int));
            memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
        }
        if (e->session_cookie) {
            s->extension.session_cookie = jk_pool_strdup(s->pool, e->session_cookie);
        }
        if (e->session_path) {
            s->extension.session_path = jk_pool_strdup(s->pool, e->session_path);
        }
        if (e->set_session_cookie) {
            s->extension.set_session_cookie = e->set_session_cookie;
        }
        if (e->session_cookie_path) {
            s->extension.session_cookie_path = jk_pool_strdup(s->pool, e->session_cookie_path);
        }

    }

    s->uw_map = uw_map;
    /*
     * Add SSL IIS environment
     */
    if (s->is_ssl) {
        char *ssl_env_names[9] = {
            "CERT_ISSUER",
            "CERT_SUBJECT",
            "CERT_COOKIE",
            "HTTPS_SERVER_SUBJECT",
            "CERT_FLAGS",
            "HTTPS_SECRETKEYSIZE",
            "CERT_SERIALNUMBER",
            "HTTPS_SERVER_ISSUER",
            "HTTPS_KEYSIZE"
        };
        char *ssl_env_values[9] = {
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL
        };
        unsigned int i;
        unsigned int num_of_vars = 0;

        for (i = 0; i < 9; i++) {
            GET_SERVER_VARIABLE_VALUE(ssl_env_names[i], ssl_env_values[i], NULL);
            if (ssl_env_values[i]) {
                num_of_vars++;
            }
        }
        /* XXX: To make the isapi plugin more consistent with the other web servers */
        /* we should also set s->ssl_cipher, s->ssl_session, and s->ssl_key_size. */
        if (num_of_vars) {
            unsigned int j = 0;

            s->attributes_names  = jk_pool_alloc(&private_data->p,
                                                 num_of_vars * sizeof(char *));
            s->attributes_values = jk_pool_alloc(&private_data->p,
                                                 num_of_vars * sizeof(char *));
            if (!s->attributes_names || !s->attributes_values) {
                JK_TRACE_EXIT(l);
                return JK_FALSE;
            }
            for (i = 0; i < 9; i++) {
                if (ssl_env_values[i]) {
                    s->attributes_names[j] = ssl_env_names[i];
                    s->attributes_values[j] = ssl_env_values[i];
                    j++;
                }
            }
            s->num_attributes = num_of_vars;
            if (ssl_env_values[4] && ssl_env_values[4][0] == '1') {
                CERT_CONTEXT_EX cc;
                BYTE *cb = jk_pool_alloc(&private_data->p, AJP13_MAX_PACKET_SIZE);

                if (!cb) {
                    JK_TRACE_EXIT(l);
                    return JK_FALSE;
                }
                cc.cbAllocated = AJP13_MAX_PACKET_SIZE;
                cc.CertContext.pbCertEncoded = cb;
                cc.CertContext.cbCertEncoded = 0;

                if (private_data->lpEcb->ServerSupportFunction(private_data->lpEcb->ConnID,
                                          HSE_REQ_GET_CERT_INFO_EX,
                                          &cc, NULL, NULL) != FALSE) {
                    jk_log(l, JK_LOG_DEBUG,
                           "Client Certificate encoding:%d sz:%d flags:%ld",
                           cc.CertContext.
                           dwCertEncodingType & X509_ASN_ENCODING,
                           cc.CertContext.cbCertEncoded,
                           cc.dwCertificateFlags);
                    s->ssl_cert = jk_pool_alloc(&private_data->p,
                                                base64_encode_cert_len(cc.CertContext.cbCertEncoded));
                    s->ssl_cert_len = base64_encode_cert(s->ssl_cert, cb,
                                                         cc.CertContext.cbCertEncoded) - 1;
                }
            }
        }
    }

    GET_SERVER_VARIABLE_VALUE(ALL_HEADERS, all_headers, NULL);
    if (!all_headers) {
        JK_TRACE_EXIT(l);
        return JK_FALSE;
    }
    for (tmp = all_headers; *tmp; tmp++) {
        if (*tmp == '\n') {
            cnt++;
        }
    }

    if (cnt) {
        char *headers_buf = all_headers;
        unsigned int i;
        BOOL need_content_length_header = FALSE;

        if (s->content_length == 0 && unknown_content_length == FALSE) {
            /* Add content-length=0 only if really zero
             */
            need_content_length_header = TRUE;
        }

        /* allocate an extra header slot in case we need to add a content-length header */
        s->headers_names  = jk_pool_alloc(&private_data->p,
                                         (cnt + 1) * sizeof(char *));
        s->headers_values = jk_pool_alloc(&private_data->p,
                                         (cnt + 1) * sizeof(char *));
        if (!s->headers_names || !s->headers_values) {
            JK_TRACE_EXIT(l);
            return JK_FALSE;
        }

        for (i = 0, tmp = headers_buf; *tmp && i < cnt;) {
            int real_header = JK_TRUE;

#ifdef USE_CGI_HEADERS
            /* Skip the HTTP_ prefix to the beginning of the header name */
            tmp += HTTP_HEADER_PREFIX_LEN;
#endif

            if (!strnicmp(tmp, URI_HEADER_NAME, strlen(URI_HEADER_NAME)) ||
                !strnicmp(tmp, WORKER_HEADER_NAME, strlen(WORKER_HEADER_NAME)) ||
                !strnicmp(tmp, WORKER_HEADER_INDEX, strlen(WORKER_HEADER_INDEX)) ||
                !strnicmp(tmp, QUERY_HEADER_NAME, strlen(QUERY_HEADER_NAME)) ||
                !strnicmp(tmp, REQUEST_ID_HEADER_NAME, strlen(REQUEST_ID_HEADER_NAME))) {
                /* Skip redirector headers */
                cnt--;
                real_header = JK_FALSE;
            }
            else if (!strnicmp(tmp, CONTENT_LENGTH,
                               sizeof(CONTENT_LENGTH) - 1)) {
                need_content_length_header = FALSE;

                /* If the content-length is unknown
                 * or larger then 4Gb do not send it.
                 * IIS can also create a synthetic Content-Length header to make
                 * lpcbTotalBytes and the CONTENT_LENGTH server variable agree
                 * on small requests where the entire chunk encoded message is
                 * read into the available buffer.
                 */
                if (unknown_content_length || s->is_chunked) {
                    if (JK_IS_DEBUG_LEVEL(l)) {
                        jk_log(l, JK_LOG_DEBUG,
                               "Disregarding Content-Length in request - content is %s",
                               s->is_chunked ? "chunked" : "unknown length");
                    }
                    cnt--;
                    real_header = JK_FALSE;
                }
                else {
                    s->headers_names[i] = tmp;
                }
            }
            else if (!strnicmp(tmp, TOMCAT_TRANSLATE_HEADER_NAME,
                               strlen(TOMCAT_TRANSLATE_HEADER_NAME))) {
                s->headers_names[i] = TRANSLATE_HEADER_NAME_LC;
            }
            else {
                s->headers_names[i] = tmp;
            }

            while (':' != *tmp && *tmp) {
#ifdef USE_CGI_HEADERS
                if (real_header) {
                    if ('_' == *tmp) {
                        *tmp = '-';
                    }
                    else {
                        *tmp = JK_TOLOWER(*tmp);
                    }
                }
#endif
                tmp++;
            }
            *tmp++ = '\0';

            /* Skip all the WS chars after the ':' to the beginning of the header value */
            while (' ' == *tmp || '\t' == *tmp || '\v' == *tmp) {
                tmp++;
            }

            if (real_header) {
                s->headers_values[i] = tmp;
            }

            while (*tmp && *tmp != '\n' && *tmp != '\r') {
                tmp++;
            }
            *tmp++ = '\0';
            /* skip CR LF */
            while (*tmp == '\n' || *tmp == '\r') {
                tmp++;
            }

            if (real_header) {
                if (JK_IS_DEBUG_LEVEL(l)) {
                    jk_log(l, JK_LOG_DEBUG, "Forwarding request header %s : %s",
                           s->headers_names[i], s->headers_values[i]);
                }
                i++;
            }
        }
        /* Add a content-length = 0 header if needed.
         * Ajp13 assumes an absent content-length header means an unknown,
         * but non-zero length body.
         */
        if (need_content_length_header) {
            if (JK_IS_DEBUG_LEVEL(l)) {
                jk_log(l, JK_LOG_DEBUG, "Incoming request needs explicit Content-Length: 0 in AJP13");
            }
            s->headers_names[cnt] = "Content-Length";
            s->headers_values[cnt] = "0";
            cnt++;
        }
        s->num_headers = cnt;
    }
    else {
        JK_TRACE_EXIT(l);
        return JK_FALSE;
    }

    /* Dump all connection param so we can trace what's going to
     * the remote tomcat
     */
    if (JK_IS_DEBUG_LEVEL(l)) {
        jk_log(l, JK_LOG_DEBUG,
               "Service protocol=%s method=%s host=%s addr=%s name=%s port=%d "
               "auth=%s user=%s uri=%s",
               STRNULL_FOR_NULL(s->protocol),
               STRNULL_FOR_NULL(s->method),
               STRNULL_FOR_NULL(s->remote_host),
               STRNULL_FOR_NULL(s->remote_addr),
               STRNULL_FOR_NULL(s->server_name),
               s->server_port,
               STRNULL_FOR_NULL(s->auth_type),
               STRNULL_FOR_NULL(s->remote_user),
               STRNULL_FOR_NULL(s->req_uri));
        jk_log(l, JK_LOG_DEBUG,
               "Service request headers=%d attributes=%d "
               "chunked=%s content-length=%" JK_UINT64_T_FMT " available=%u",
               s->num_headers,
               s->num_attributes,
               (s->is_chunked == JK_TRUE) ? "yes" : "no",
               s->content_length,
               private_data->lpEcb->cbTotalBytes);
    }

    JK_TRACE_EXIT(l);
    return JK_TRUE;
}