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;
}