blob: 753e9458553b9eee0c2c2890d5c0a4c167003f5f [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "jk_global.h"
#include "jk_service.h"
#include "jk_msg.h"
#include "jk_env.h"
#include "jk_requtil.h"
#include "jk_env.h"
#include "jk_handler.h"
#include "jk_endpoint.h"
#include "jk_registry.h"
/** SEND_HEADERS handler
AJPV13_RESPONSE/AJPV14_RESPONSE:=
response_prefix (2)
status (short)
status_msg (short)
num_headers (short)
num_headers*(res_header_name header_value)
*body_chunk
terminator boolean <! -- recycle connection or not -->
req_header_name :=
sc_req_header_name | (string)
res_header_name :=
sc_res_header_name | (string)
header_value :=
(string)
body_chunk :=
length (short)
body length*(var binary)
*/
static int JK_METHOD jk2_handler_startResponse(jk_env_t *env, void *target,
jk_endpoint_t *ae,
jk_msg_t *msg)
{
jk_ws_service_t *s = target;
int err = JK_ERR;
int i;
jk_pool_t *pool = s->pool;
int headerCount;
int debug = 1;
if (s->uriEnv != NULL)
debug = s->uriEnv->mbean->debug;
s->status = msg->getInt(env, msg);
s->msg = (char *)msg->getString(env, msg);
if (s->msg) {
jk_xlate_from_ascii(s->msg, strlen(s->msg));
/* Do we want this ? Probably not needed, but safer ! */
s->msg = ae->cPool->pstrdup(env, ae->cPool, s->msg);
}
headerCount = msg->getInt(env, msg);
/* XXX assert msg->headers_out is set - the server adapter should know what
kind of map to use ! */
for (i = 0; i < headerCount; i++) {
char *nameS;
char *valueS;
unsigned short name = msg->peekInt(env, msg);
if ((name & 0XFF00) == 0XA000) {
msg->getInt(env, msg);
name = name & 0X00FF;
if (name <= SC_RES_HEADERS_NUM) {
nameS = (char *)jk2_requtil_getHeaderById(env, name);
}
else {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"handler.response() Invalid header id (%d)\n",
name);
return JK_HANDLER_FATAL;
}
}
else {
nameS = (char *)msg->getString(env, msg);
if (nameS == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"handler.response() Null header name \n");
return JK_HANDLER_FATAL;
}
jk_xlate_from_ascii(nameS, strlen(nameS));
}
valueS = (char *)msg->getString(env, msg);
if (valueS == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"Error ajp_unmarshal_response - Null header value\n");
return JK_HANDLER_FATAL;
}
jk_xlate_from_ascii(valueS, strlen(valueS));
if (debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"handler.response() Header[%d] [%s] = [%s]\n",
i, nameS, valueS);
/* Do we want this ? Preserve the headers, maybe someone will
need them. Alternative is to use a different buffer every time,
which may be more efficient. */
/* We probably don't need that, we'll send them in the next call */
/*Apache does it - will change if we add jk_map_apache
nameS=ae->cPool->pstrdup( ae->cPool, nameS ); */
/* valueS=ae->cPool->pstrdup( ae->cPool, valueS ); */
s->headers_out->add(env, s->headers_out, nameS, valueS);
}
if (debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"handler.response(): status=%d headers=%d\n",
s->status, headerCount);
err = s->head(env, s);
if (err != JK_OK) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"handler.response() Error sending response");
return JK_HANDLER_ERROR;
}
return JK_HANDLER_OK;
}
/** SEND_BODY_CHUNK handler
*/
static int JK_METHOD jk2_handler_sendChunk(jk_env_t *env, void *target,
jk_endpoint_t *ae, jk_msg_t *msg)
{
jk_ws_service_t *r = target;
int err;
int len;
char *buf;
buf = msg->getBytes(env, msg, &len);
err = r->write(env, r, buf, len);
if (err != JK_OK) {
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"Write failed - user closed connection or other network problems\n");
return JK_HANDLER_ERROR;
}
return JK_HANDLER_OK;
}
static int JK_METHOD jk2_handler_endResponse(jk_env_t *env, void *target,
jk_endpoint_t *ae, jk_msg_t *msg)
{
int reuse = (int)msg->getByte(env, msg);
if ((reuse & 0X01) != reuse) {
/*
* Strange protocol error.
*/
reuse = JK_FALSE;
}
if (reuse == JK_FALSE)
ae->recoverable = JK_FALSE;
return JK_HANDLER_LAST;
}
/** GET_BODY_CHUNK handler
*/
static int JK_METHOD jk2_handler_getChunk(jk_env_t *env, void *target,
jk_endpoint_t *ae, jk_msg_t *msg)
{
jk_ws_service_t *r = target;
int len = msg->getInt(env, msg);
if (len > AJP13_MAX_SEND_BODY_SZ) {
len = AJP13_MAX_SEND_BODY_SZ;
}
if (len > r->left_bytes_to_send) {
len = r->left_bytes_to_send;
}
if (len < 0) {
len = 0;
}
/* env->l->jkLog(env, env->l, JK_LOG_INFO, */
/* "handler_request.getChunk() - read len=%d\n",len); */
msg->reset(env, msg);
len = msg->appendFromServer(env, msg, r, ae, len);
/* the right place to add file storage for upload */
if (len >= 0) {
r->content_read += len;
return JK_HANDLER_RESPONSE;
}
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"handler_request.getChunk() - read failed len=%d\n", len);
return JK_HANDLER_FATAL;
}
/** PONG Reply handler
*/
static int JK_METHOD jk2_handler_getPong(jk_env_t *env, void *target,
jk_endpoint_t *ae, jk_msg_t *msg)
{
return JK_HANDLER_LAST;
}
static int JK_METHOD jk2_handler_response_invoke(jk_env_t *env,
jk_bean_t *bean,
jk_endpoint_t *ep, int code,
jk_msg_t *msg, int raw)
{
void *target = ep->currentRequest;
switch (code) {
case JK_HANDLE_AJP13_SEND_HEADERS:
return jk2_handler_startResponse(env, target, ep, msg);
case JK_HANDLE_AJP13_SEND_BODY_CHUNK:
return jk2_handler_sendChunk(env, target, ep, msg);
case JK_HANDLE_AJP13_END_RESPONSE:
return jk2_handler_endResponse(env, target, ep, msg);
case JK_HANDLE_AJP13_GET_BODY_CHUNK:
return jk2_handler_getChunk(env, target, ep, msg);
case JK_HANDLE_AJP13_PONG_REPLY:
return jk2_handler_getPong(env, target, ep, msg);
}
return JK_OK;
}
static int JK_METHOD jk2_handler_response_init(jk_env_t *env,
jk_handler_t * _this,
jk_workerEnv_t *wEnv)
{
wEnv->registerHandler(env, wEnv, "handler.response",
"sendHeaders", JK_HANDLE_AJP13_SEND_HEADERS,
jk2_handler_startResponse, NULL);
wEnv->registerHandler(env, wEnv, "handler.response",
"sendChunk", JK_HANDLE_AJP13_SEND_BODY_CHUNK,
jk2_handler_sendChunk, NULL);
wEnv->registerHandler(env, wEnv, "handler.response",
"endResponse", JK_HANDLE_AJP13_END_RESPONSE,
jk2_handler_endResponse, NULL);
wEnv->registerHandler(env, wEnv, "handler.response",
"getChunk", JK_HANDLE_AJP13_GET_BODY_CHUNK,
jk2_handler_getChunk, NULL);
wEnv->registerHandler(env, wEnv, "handler.response",
"pongResponse", JK_HANDLE_AJP13_PONG_REPLY,
jk2_handler_getPong, NULL);
return JK_OK;
}
int JK_METHOD jk2_handler_response_factory(jk_env_t *env, jk_pool_t *pool,
jk_bean_t *result,
const char *type, const char *name)
{
jk_handler_t *h;
h = (jk_handler_t *) pool->calloc(env, pool, sizeof(jk_handler_t));
h->init = jk2_handler_response_init;
result->invoke = jk2_handler_response_invoke;
result->object = h;
return JK_OK;
}