You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by hg...@apache.org on 2001/05/03 15:59:57 UTC
cvs commit: jakarta-tomcat/proposals/web-connector/native/common jk_ajp13.c jk_ajp13.h jk_ajp13_worker.c jk_ajp13_worker.h
hgomez 01/05/03 06:59:57
Added: proposals/web-connector/native/common jk_ajp13.c jk_ajp13.h
jk_ajp13_worker.c jk_ajp13_worker.h
Log:
ajp13 protocol handling
Revision Changes Path
1.1 jakarta-tomcat/proposals/web-connector/native/common/jk_ajp13.c
Index: jk_ajp13.c
===================================================================
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/***************************************************************************
* Description: Experimental bi-directionl protocol handler. *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Version: $Revision: 1.1 $ *
***************************************************************************/
#include "jk_global.h"
#include "jk_util.h"
#include "jk_ajp13.h"
/*
* Conditional request attributes
*
*/
#define SC_A_CONTEXT (unsigned char)1
#define SC_A_SERVLET_PATH (unsigned char)2
#define SC_A_REMOTE_USER (unsigned char)3
#define SC_A_AUTH_TYPE (unsigned char)4
#define SC_A_QUERY_STRING (unsigned char)5
#define SC_A_JVM_ROUTE (unsigned char)6
#define SC_A_SSL_CERT (unsigned char)7
#define SC_A_SSL_CIPHER (unsigned char)8
#define SC_A_SSL_SESSION (unsigned char)9
#define SC_A_REQ_ATTRIBUTE (unsigned char)10
#define SC_A_ARE_DONE (unsigned char)0xFF
/*
* Request methods, coded as numbers instead of strings.
* The list of methods was taken from Section 5.1.1 of RFC 2616,
* RFC 2518, and the ACL IETF draft.
* Method = "OPTIONS"
* | "GET"
* | "HEAD"
* | "POST"
* | "PUT"
* | "DELETE"
* | "TRACE"
* | "PROPFIND"
* | "PROPPATCH"
* | "MKCOL"
* | "COPY"
* | "MOVE"
* | "LOCK"
* | "UNLOCK"
* | "ACL"
*
*/
#define SC_M_OPTIONS (unsigned char)1
#define SC_M_GET (unsigned char)2
#define SC_M_HEAD (unsigned char)3
#define SC_M_POST (unsigned char)4
#define SC_M_PUT (unsigned char)5
#define SC_M_DELETE (unsigned char)6
#define SC_M_TRACE (unsigned char)7
#define SC_M_PROPFIND (unsigned char)8
#define SC_M_PROPPATCH (unsigned char)9
#define SC_M_MKCOL (unsigned char)10
#define SC_M_COPY (unsigned char)11
#define SC_M_MOVE (unsigned char)12
#define SC_M_LOCK (unsigned char)13
#define SC_M_UNLOCK (unsigned char)14
#define SC_M_ACL (unsigned char)15
/*
* Frequent request headers, these headers are coded as numbers
* instead of strings.
*
* Accept
* Accept-Charset
* Accept-Encoding
* Accept-Language
* Authorization
* Connection
* Content-Type
* Content-Length
* Cookie
* Cookie2
* Host
* Pragma
* Referer
* User-Agent
*
*/
#define SC_ACCEPT (unsigned short)0xA001
#define SC_ACCEPT_CHARSET (unsigned short)0xA002
#define SC_ACCEPT_ENCODING (unsigned short)0xA003
#define SC_ACCEPT_LANGUAGE (unsigned short)0xA004
#define SC_AUTHORIZATION (unsigned short)0xA005
#define SC_CONNECTION (unsigned short)0xA006
#define SC_CONTENT_TYPE (unsigned short)0xA007
#define SC_CONTENT_LENGTH (unsigned short)0xA008
#define SC_COOKIE (unsigned short)0xA009
#define SC_COOKIE2 (unsigned short)0xA00A
#define SC_HOST (unsigned short)0xA00B
#define SC_PRAGMA (unsigned short)0xA00C
#define SC_REFERER (unsigned short)0xA00D
#define SC_USER_AGENT (unsigned short)0xA00E
/*
* Frequent response headers, these headers are coded as numbers
* instead of strings.
*
* Content-Type
* Content-Language
* Content-Length
* Date
* Last-Modified
* Location
* Set-Cookie
* Servlet-Engine
* Status
* WWW-Authenticate
*
*/
#define SC_RESP_CONTENT_TYPE (unsigned short)0xA001
#define SC_RESP_CONTENT_LANGUAGE (unsigned short)0xA002
#define SC_RESP_CONTENT_LENGTH (unsigned short)0xA003
#define SC_RESP_DATE (unsigned short)0xA004
#define SC_RESP_LAST_MODIFIED (unsigned short)0xA005
#define SC_RESP_LOCATION (unsigned short)0xA006
#define SC_RESP_SET_COOKIE (unsigned short)0xA007
#define SC_RESP_SET_COOKIE2 (unsigned short)0xA008
#define SC_RESP_SERVLET_ENGINE (unsigned short)0xA009
#define SC_RESP_STATUS (unsigned short)0xA00A
#define SC_RESP_WWW_AUTHENTICATE (unsigned short)0xA00B
#define SC_RES_HEADERS_NUM 11
const char *response_trans_headers[] = {
"Content-Type",
"Content-Language",
"Content-Length",
"Date",
"Last-Modified",
"Location",
"Set-Cookie",
"Set-Cookie2",
"Servlet-Engine",
"Status",
"WWW-Authenticate"
};
const char *long_res_header_for_sc(int sc)
{
const char *rc = NULL;
if(sc <= SC_RES_HEADERS_NUM && sc > 0) {
rc = response_trans_headers[sc - 1];
}
return rc;
}
int sc_for_req_method(const char *method,
unsigned char *sc)
{
int rc = JK_TRUE;
if(0 == strcmp(method, "GET")) {
*sc = SC_M_GET;
} else if(0 == strcmp(method, "POST")) {
*sc = SC_M_POST;
} else if(0 == strcmp(method, "HEAD")) {
*sc = SC_M_HEAD;
} else if(0 == strcmp(method, "PUT")) {
*sc = SC_M_PUT;
} else if(0 == strcmp(method, "DELETE")) {
*sc = SC_M_DELETE;
} else if(0 == strcmp(method, "OPTIONS")) {
*sc = SC_M_OPTIONS;
} else if(0 == strcmp(method, "TRACE")) {
*sc = SC_M_TRACE;
} else if(0 == strcmp(method, "PROPFIND")) {
*sc = SC_M_PROPFIND;
} else if(0 == strcmp(method, "PROPPATCH")) {
*sc = SC_M_PROPPATCH;
} else if(0 == strcmp(method, "MKCOL")) {
*sc = SC_M_MKCOL;
} else if(0 == strcmp(method, "COPY")) {
*sc = SC_M_COPY;
} else if(0 == strcmp(method, "MOVE")) {
*sc = SC_M_MOVE;
} else if(0 == strcmp(method, "LOCK")) {
*sc = SC_M_LOCK;
} else if(0 == strcmp(method, "UNLOCK")) {
*sc = SC_M_UNLOCK;
} else if(0 == strcmp(method, "ACL")) {
*sc = SC_M_ACL;
} else {
rc = JK_FALSE;
}
return rc;
}
int sc_for_req_header(const char *header_name,
unsigned short *sc)
{
switch(header_name[0]) {
case 'a':
if('c' ==header_name[1] &&
'c' ==header_name[2] &&
'e' ==header_name[3] &&
'p' ==header_name[4] &&
't' ==header_name[5]) {
if('-' == header_name[6]) {
if(!strcmp(header_name + 7, "charset")) {
*sc = SC_ACCEPT_CHARSET;
} else if(!strcmp(header_name + 7, "encoding")) {
*sc = SC_ACCEPT_ENCODING;
} else if(!strcmp(header_name + 7, "language")) {
*sc = SC_ACCEPT_LANGUAGE;
} else {
return JK_FALSE;
}
} else if('\0' == header_name[6]) {
*sc = SC_ACCEPT;
} else {
return JK_FALSE;
}
} else if(!strcmp(header_name, "authorization")) {
*sc = SC_AUTHORIZATION;
} else {
return JK_FALSE;
}
break;
case 'c':
if(!strcmp(header_name, "cookie")) {
*sc = SC_COOKIE;
} else if(!strcmp(header_name, "connection")) {
*sc = SC_CONNECTION;
} else if(!strcmp(header_name, "content-type")) {
*sc = SC_CONTENT_TYPE;
} else if(!strcmp(header_name, "content-length")) {
*sc = SC_CONTENT_LENGTH;
} else if(!strcmp(header_name, "cookie2")) {
*sc = SC_COOKIE2;
} else {
return JK_FALSE;
}
break;
case 'h':
if(!strcmp(header_name, "host")) {
*sc = SC_HOST;
} else {
return JK_FALSE;
}
break;
case 'p':
if(!strcmp(header_name, "pragma")) {
*sc = SC_PRAGMA;
} else {
return JK_FALSE;
}
break;
case 'r':
if(!strcmp(header_name, "referer")) {
*sc = SC_REFERER;
} else {
return JK_FALSE;
}
break;
case 'u':
if(!strcmp(header_name, "user-agent")) {
*sc = SC_USER_AGENT;
} else {
return JK_FALSE;
}
break;
default:
return JK_FALSE;
}
return JK_TRUE;
}
/*
* Message structure
*
*
AJPV13_REQUEST:=
request_prefix (1) (byte)
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (short)
is_ssl (boolean)
num_headers (short)
num_headers*(req_header_name header_value)
?context (byte)(string)
?servlet_path (byte)(string)
?remote_user (byte)(string)
?auth_type (byte)(string)
?query_string (byte)(string)
?jvm_route (byte)(string)
?ssl_cert (byte)(string)
?ssl_cipher (byte)(string)
?ssl_session (byte)(string)
request_terminator (byte)
?body content_length*(var binary)
*/
int ajp13_marshal_into_msgb(jk_msg_buf_t *msg,
jk_ws_service_t *s,
jk_logger_t *l)
{
unsigned char method;
unsigned i;
jk_log(l, JK_LOG_DEBUG,
"Into ajp13_marshal_into_msgb\n");
if(!sc_for_req_method(s->method, &method)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - No such method %s\n", s->method);
return JK_FALSE;
}
if(0 != jk_b_append_byte(msg, JK_AJP13_FORWARD_REQUEST) ||
0 != jk_b_append_byte(msg, method) ||
0 != jk_b_append_string(msg, s->protocol) ||
0 != jk_b_append_string(msg, s->req_uri) ||
0 != jk_b_append_string(msg, s->remote_addr) ||
0 != jk_b_append_string(msg, s->remote_host) ||
0 != jk_b_append_string(msg, s->server_name) ||
0 != jk_b_append_int(msg, (unsigned short)s->server_port) ||
0 != jk_b_append_byte(msg, (unsigned char)(s->is_ssl)) ||
0 != jk_b_append_int(msg, (unsigned short)(s->num_headers))) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the message begining\n");
return JK_FALSE;
}
for(i = 0 ; i < s->num_headers ; i++) {
unsigned short sc;
if(sc_for_req_header(s->headers_names[i], &sc) ) {
if(0 != jk_b_append_int(msg, sc)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the header name\n");
return JK_FALSE;
}
} else {
if(0 != jk_b_append_string(msg, s->headers_names[i])) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the header name\n");
return JK_FALSE;
}
}
if(0 != jk_b_append_string(msg, s->headers_values[i])) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the header value\n");
return JK_FALSE;
}
}
if(s->remote_user) {
if(0 != jk_b_append_byte(msg, SC_A_REMOTE_USER) ||
0 != jk_b_append_string(msg, s->remote_user)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the remote user\n");
return JK_FALSE;
}
}
if(s->auth_type) {
if(0 != jk_b_append_byte(msg, SC_A_AUTH_TYPE) ||
0 != jk_b_append_string(msg, s->auth_type)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the auth type\n");
return JK_FALSE;
}
}
if(s->query_string) {
if(0 != jk_b_append_byte(msg, SC_A_QUERY_STRING) ||
0 != jk_b_append_string(msg, s->query_string)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the query string\n");
return JK_FALSE;
}
}
if(s->jvm_route) {
if(0 != jk_b_append_byte(msg, SC_A_JVM_ROUTE) ||
0 != jk_b_append_string(msg, s->jvm_route)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the jvm route\n");
return JK_FALSE;
}
}
if(s->ssl_cert_len) {
if(0 != jk_b_append_byte(msg, SC_A_SSL_CERT) ||
0 != jk_b_append_string(msg, s->ssl_cert)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the SSL certificates\n");
return JK_FALSE;
}
}
if(s->ssl_cipher) {
if(0 != jk_b_append_byte(msg, SC_A_SSL_CIPHER) ||
0 != jk_b_append_string(msg, s->ssl_cipher)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the SSL ciphers\n");
return JK_FALSE;
}
}
if(s->ssl_session) {
if(0 != jk_b_append_byte(msg, SC_A_SSL_SESSION) ||
0 != jk_b_append_string(msg, s->ssl_session)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the SSL session\n");
return JK_FALSE;
}
}
if(s->num_attributes > 0) {
for(i = 0 ; i < s->num_attributes ; i++) {
if(0 != jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) ||
0 != jk_b_append_string(msg, s->attributes_names[i]) ||
0 != jk_b_append_string(msg, s->attributes_values[i])) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending attribute %s=%s\n",
s->attributes_names[i], s->attributes_values[i]);
return JK_FALSE;
}
}
}
if(0 != jk_b_append_byte(msg, SC_A_ARE_DONE)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_marshal_into_msgb - Error appending the message end\n");
return JK_FALSE;
}
jk_log(l, JK_LOG_DEBUG,
"ajp13_marshal_into_msgb - Done\n");
return JK_TRUE;
}
/*
AJPV13_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)
*/
int ajp13_unmarshal_response(jk_msg_buf_t *msg,
jk_res_data_t *d,
jk_pool_t *p,
jk_logger_t *l)
{
d->status = jk_b_get_int(msg);
if(!d->status) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_unmarshal_response - Null status\n");
return JK_FALSE;
}
d->msg = (char *)jk_b_get_string(msg);
jk_log(l, JK_LOG_DEBUG,
"ajp13_unmarshal_response: status = %d\n",
d->status);
d->num_headers = jk_b_get_int(msg);
d->header_names = d->header_values = NULL;
jk_log(l, JK_LOG_DEBUG,
"ajp13_unmarshal_response: Number of headers is = %d\n",
d->num_headers);
if(d->num_headers) {
d->header_names = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
d->header_values = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
if(d->header_names && d->header_values) {
unsigned i;
for(i = 0 ; i < d->num_headers ; i++) {
unsigned short name = jk_b_pget_int(msg, jk_b_get_pos(msg)) ;
if((name & 0XFF00) == 0XA000) {
jk_b_get_int(msg);
name = name & 0X00FF;
if(name <= SC_RES_HEADERS_NUM) {
d->header_names[i] = (char *)long_res_header_for_sc(name);
} else {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_unmarshal_response - No such sc (%d)\n",
name);
return JK_FALSE;
}
} else {
d->header_names[i] = (char *)jk_b_get_string(msg);
if(!d->header_names[i]) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_unmarshal_response - Null header name\n");
return JK_FALSE;
}
}
d->header_values[i] = (char *)jk_b_get_string(msg);
if(!d->header_values[i]) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_unmarshal_response - Null header value\n");
return JK_FALSE;
}
jk_log(l, JK_LOG_DEBUG,
"ajp13_unmarshal_response: Header[%d] [%s] = [%s]\n",
i,
d->header_names[i],
d->header_values[i]);
}
}
}
return JK_TRUE;
}
int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
jk_pool_t *p,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG,
"Into ajp13_marshal_shutdown_into_msgb\n");
/* To be on the safe side */
jk_b_reset(msg);
/*
* Just a single byte with s/d command.
*/
if(0 != jk_b_append_byte(msg, JK_AJP13_SHUTDOWN)) {
return JK_FALSE;
}
return JK_TRUE;
}
1.1 jakarta-tomcat/proposals/web-connector/native/common/jk_ajp13.h
Index: jk_ajp13.h
===================================================================
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/***************************************************************************
* Description: Experimental bi-directionl protocol handler. *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Version: $Revision: 1.1 $ *
***************************************************************************/
#ifndef JK_AJP13_H
#define JK_AJP13_H
#include "jk_service.h"
#include "jk_msg_buff.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Message does not have a response (for example, JK_AJP13_END_RESPONSE)
*/
#define JK_AJP13_ERROR -1
/*
* Message does not have a response (for example, JK_AJP13_END_RESPONSE)
*/
#define JK_AJP13_NO_RESPONSE 0
/*
* Message have a response.
*/
#define JK_AJP13_HAS_RESPONSE 1
/*
* Forward a request from the web server to the servlet container.
*/
#define JK_AJP13_FORWARD_REQUEST (unsigned char)2
/*
* Write a body chunk from the servlet container to the web server
*/
#define JK_AJP13_SEND_BODY_CHUNK (unsigned char)3
/*
* Send response headers from the servlet container to the web server.
*/
#define JK_AJP13_SEND_HEADERS (unsigned char)4
/*
* Marks the end of response.
*/
#define JK_AJP13_END_RESPONSE (unsigned char)5
/*
* Marks the end of response.
*/
#define JK_AJP13_GET_BODY_CHUNK (unsigned char)6
/*
* Asks the container to shutdown
*/
#define JK_AJP13_SHUTDOWN (unsigned char)7
struct jk_res_data {
int status;
const char *msg;
unsigned num_headers;
char **header_names;
char **header_values;
};
typedef struct jk_res_data jk_res_data_t;
int ajp13_marshal_into_msgb(jk_msg_buf_t *msg,
jk_ws_service_t *s,
jk_logger_t *l);
int ajp13_unmarshal_response(jk_msg_buf_t *msg,
jk_res_data_t *d,
jk_pool_t *p,
jk_logger_t *l);
int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
jk_pool_t *p,
jk_logger_t *l);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* JK_AJP13_H */
1.1 jakarta-tomcat/proposals/web-connector/native/common/jk_ajp13_worker.c
Index: jk_ajp13_worker.c
===================================================================
/*
* Copyright (c) 1997-2001 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/***************************************************************************
* Description: Bi-directional protocol. *
* Author: Henri Gomez <hg...@slib.fr> *
* Author: Costin <co...@costin.dnt.ro> *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Version: $Revision: 1.1 $ *
***************************************************************************/
#include "jk_pool.h"
#include "jk_connect.h"
#include "jk_util.h"
#include "jk_msg_buff.h"
#include "jk_ajp13.h"
#include "jk_mt.h"
#define AJP_DEF_HOST ("localhost")
#define AJP_DEF_PORT (8008)
#define READ_BUF_SIZE (8*1024)
#define DEF_RETRY_ATTEMPTS (1)
#define DEF_CACHE_SZ (1)
#define JK_INTERNAL_ERROR (-2)
#define MAX_SEND_BODY_SZ (DEF_BUFFER_SZ - 6)
#define AJP13_HEADER_LEN (4)
#define AJP13_HEADER_SZ_LEN (2)
struct ajp13_operation;
typedef struct ajp13_operation ajp13_operation_t;
struct ajp13_endpoint;
typedef struct ajp13_endpoint ajp13_endpoint_t;
struct ajp13_worker {
struct sockaddr_in worker_inet_addr; /* Contains host and port */
unsigned connect_retry_attempts;
char *name;
/*
* Open connections cache...
*
* 1. Critical section object to protect the cache.
* 2. Cache size.
* 3. An array of "open" endpoints.
*/
JK_CRIT_SEC cs;
unsigned ep_cache_sz;
ajp13_endpoint_t **ep_cache;
jk_worker_t worker;
};
typedef struct ajp13_worker ajp13_worker_t;
struct ajp13_endpoint {
ajp13_worker_t *worker;
jk_pool_t pool;
jk_pool_atom_t buf[BIG_POOL_SIZE];
int sd;
int reuse;
jk_endpoint_t endpoint;
unsigned left_bytes_to_send;
};
/*
* little struct to avoid multiples ptr passing
* this struct is ready to hold upload file fd
* to add upload persistant storage
*/
struct ajp13_operation {
jk_msg_buf_t *request; /* original request storage */
jk_msg_buf_t *reply; /* reply storage (chuncked by ajp13 */
int uploadfd; /* future persistant storage id */
int recoverable; /* if exchange could be conducted on another TC */
};
static void reset_endpoint(ajp13_endpoint_t *ep)
{
ep->reuse = JK_FALSE;
jk_reset_pool(&(ep->pool));
}
static void close_endpoint(ajp13_endpoint_t *ep)
{
reset_endpoint(ep);
if(ep->sd > 0) {
jk_close_socket(ep->sd);
}
free(ep);
}
static void reuse_connection(ajp13_endpoint_t *ep,
jk_logger_t *l)
{
ajp13_worker_t *w = ep->worker;
if(w->ep_cache_sz) {
int rc;
JK_ENTER_CS(&w->cs, rc);
if(rc) {
unsigned i;
for(i = 0 ; i < w->ep_cache_sz ; i++) {
if(w->ep_cache[i]) {
ep->sd = w->ep_cache[i]->sd;
w->ep_cache[i]->sd = -1;
close_endpoint(w->ep_cache[i]);
w->ep_cache[i] = NULL;
break;
}
}
JK_LEAVE_CS(&w->cs, rc);
}
}
}
static void connect_to_tomcat(ajp13_endpoint_t *ep,
jk_logger_t *l)
{
unsigned attempt;
for(attempt = 0 ; attempt < ep->worker->connect_retry_attempts ; attempt++) {
ep->sd = jk_open_socket(&ep->worker->worker_inet_addr,
JK_TRUE,
l);
if(ep->sd >= 0) {
jk_log(l,
JK_LOG_DEBUG,
"In jk_endpoint_t::connect_to_tomcat, connected sd = %d\n", ep->sd);
return;
}
}
jk_log(l,
JK_LOG_ERROR,
"In jk_endpoint_t::connect_to_tomcat, failed errno = %d\n", errno);
}
static int connection_tcp_send_message(ajp13_endpoint_t *ep,
jk_msg_buf_t *msg,
jk_logger_t *l )
{
jk_b_end(msg);
jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg);
if(0 > jk_tcp_socket_sendfull(ep->sd,
jk_b_get_buff(msg),
jk_b_get_len(msg))) {
return JK_FALSE;
}
return JK_TRUE;
}
static int connection_tcp_get_message(ajp13_endpoint_t *ep,
jk_msg_buf_t *msg,
jk_logger_t *l)
{
unsigned char head[AJP13_HEADER_LEN];
int rc;
int msglen;
rc = jk_tcp_socket_recvfull(ep->sd, head, AJP13_HEADER_LEN);
if(rc < 0) {
jk_log(l, JK_LOG_ERROR,
"connection_tcp_get_message: Error - jk_tcp_socket_recvfull failed\n");
return JK_FALSE;
}
if((head[0] != 'A') || (head[1] != 'B' )) {
jk_log(l, JK_LOG_ERROR,
"connection_tcp_get_message: Error - Wrong message format\n");
return JK_FALSE;
}
msglen = ((head[2]&0xff)<<8);
msglen += (head[3] & 0xFF);
if(msglen > jk_b_get_size(msg)) {
jk_log(l, JK_LOG_ERROR,
"connection_tcp_get_message: Error - Wrong message size\n");
return JK_FALSE;
}
jk_b_set_len(msg, msglen);
jk_b_set_pos(msg, 0);
rc = jk_tcp_socket_recvfull(ep->sd, jk_b_get_buff(msg), msglen);
if(rc < 0) {
jk_log(l, JK_LOG_ERROR,
"connection_tcp_get_message: Error - jk_tcp_socket_recvfull failed\n");
return JK_FALSE;
}
jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg);
return JK_TRUE;
}
static int read_fully_from_server(jk_ws_service_t *s,
unsigned char *buf,
unsigned len)
{
unsigned rdlen = 0;
while(rdlen < len) {
unsigned this_time = 0;
if(!s->read(s, buf + rdlen, len - rdlen, &this_time)) {
return -1;
}
if(0 == this_time) {
break;
}
rdlen += this_time;
}
return (int)rdlen;
}
static int read_into_msg_buff(ajp13_endpoint_t *ep,
jk_ws_service_t *r,
jk_msg_buf_t *msg,
jk_logger_t *l,
unsigned len)
{
unsigned char *read_buf = jk_b_get_buff(msg);
jk_b_reset(msg);
read_buf += AJP13_HEADER_LEN; /* leave some space for the buffer headers */
read_buf += AJP13_HEADER_SZ_LEN; /* leave some space for the read length */
if(read_fully_from_server(r, read_buf, len) < 0) {
jk_log(l, JK_LOG_ERROR,
"read_into_msg_buff: Error - read_fully_from_server failed\n");
return JK_FALSE;
}
ep->left_bytes_to_send -= len;
if(0 != jk_b_append_int(msg, (unsigned short)len)) {
jk_log(l, JK_LOG_ERROR,
"read_into_msg_buff: Error - jk_b_append_int failed\n");
return JK_FALSE;
}
jk_b_set_len(msg, jk_b_get_len(msg) + len);
return JK_TRUE;
}
static int ajp13_process_callback(jk_msg_buf_t *msg,
ajp13_endpoint_t *ep,
jk_ws_service_t *r,
jk_logger_t *l)
{
int code = (int)jk_b_get_byte(msg);
switch(code) {
case JK_AJP13_SEND_HEADERS:
{
jk_res_data_t res;
if(!ajp13_unmarshal_response(msg,
&res,
&ep->pool,
l)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_process_callback - ajp13_unmarshal_response failed\n");
return JK_AJP13_ERROR;
}
if(!r->start_response(r,
res.status,
res.msg,
(const char * const *)res.header_names,
(const char * const *)res.header_values,
res.num_headers)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_process_callback - start_response failed\n");
return JK_INTERNAL_ERROR;
}
}
break;
case JK_AJP13_SEND_BODY_CHUNK:
{
unsigned len = (unsigned)jk_b_get_int(msg);
if(!r->write(r, jk_b_get_buff(msg) + jk_b_get_pos(msg), len)) {
jk_log(l, JK_LOG_ERROR,
"Error ajp13_process_callback - write failed\n");
return JK_INTERNAL_ERROR;
}
}
break;
case JK_AJP13_GET_BODY_CHUNK:
{
unsigned len = (unsigned)jk_b_get_int(msg);
if(len > MAX_SEND_BODY_SZ) {
len = MAX_SEND_BODY_SZ;
}
if(len > ep->left_bytes_to_send) {
len = ep->left_bytes_to_send;
}
if(len < 0) {
len = 0;
}
/* the right place to add file storage for upload */
if(read_into_msg_buff(ep, r, msg, l, len)) {
r->content_read += len;
return JK_AJP13_HAS_RESPONSE;
}
jk_log(l, JK_LOG_ERROR,
"Error ajp13_process_callback - read_into_msg_buff failed\n");
return JK_INTERNAL_ERROR;
}
break;
case JK_AJP13_END_RESPONSE:
{
ep->reuse = (int)jk_b_get_byte(msg);
if((ep->reuse & 0X01) != ep->reuse) {
/*
* Strange protocol error.
*/
ep->reuse = JK_FALSE;
}
}
return JK_AJP13_END_RESPONSE;
break;
default:
jk_log(l,
JK_LOG_ERROR,
"Error ajp13_process_callback - Invalid code: %d\n", code);
return JK_AJP13_ERROR;
}
return JK_AJP13_NO_RESPONSE;
}
/* -------------------- Method -------------------- */
static int JK_METHOD validate(jk_worker_t *pThis,
jk_map_t *props,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate\n");
if(pThis && pThis->worker_private) {
ajp13_worker_t *p = pThis->worker_private;
int port = jk_get_worker_port(props,
p->name,
AJP_DEF_PORT);
char *host = jk_get_worker_host(props,
p->name,
AJP_DEF_HOST);
jk_log(l,
JK_LOG_DEBUG,
"In jk_worker_t::validate for worker %s contact is %s:%d\n",
p->name, host, port);
if(port > 1024 && host) {
if(jk_resolve(host, (short)port, &p->worker_inet_addr)) {
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, resolve failed\n");
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d\n", host, port);
} else {
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, NULL parameters\n");
}
return JK_FALSE;
}
static int JK_METHOD init(jk_worker_t *pThis,
jk_map_t *props,
jk_logger_t *l)
{
/*
* start the connection cache
*/
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::init\n");
if(pThis && pThis->worker_private) {
ajp13_worker_t *p = pThis->worker_private;
int cache_sz = jk_get_worker_cache_size(props,
p->name,
DEF_CACHE_SZ);
if(cache_sz > 0) {
p->ep_cache =
(ajp13_endpoint_t **)malloc(sizeof(ajp13_endpoint_t *) * cache_sz);
if(p->ep_cache) {
int i;
p->ep_cache_sz = cache_sz;
for(i = 0 ; i < cache_sz ; i++) {
p->ep_cache[i] = NULL;
}
JK_INIT_CS(&(p->cs), i);
if(i) {
return JK_TRUE;
}
}
}
} else {
jk_log(l,
JK_LOG_ERROR,
"In jk_worker_t::init, NULL parameters\n");
}
return JK_FALSE;
}
static int JK_METHOD destroy(jk_worker_t **pThis,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy\n");
if(pThis && *pThis && (*pThis)->worker_private) {
ajp13_worker_t *private_data = (*pThis)->worker_private;
free(private_data->name);
if(private_data->ep_cache_sz) {
unsigned i;
for(i = 0 ; i < private_data->ep_cache_sz ; i++) {
if(private_data->ep_cache[i]) {
reset_endpoint(private_data->ep_cache[i]);
close_endpoint(private_data->ep_cache[i]);
}
}
free(private_data->ep_cache);
JK_DELETE_CS(&(private_data->cs), i);
}
free(private_data);
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters\n");
return JK_FALSE;
}
static int JK_METHOD done(jk_endpoint_t **e,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done\n");
if(e && *e && (*e)->endpoint_private) {
ajp13_endpoint_t *p = (*e)->endpoint_private;
int reuse_ep = p->reuse;
reset_endpoint(p);
if(reuse_ep) {
ajp13_worker_t *w = p->worker;
if(w->ep_cache_sz) {
int rc;
JK_ENTER_CS(&w->cs, rc);
if(rc) {
unsigned i;
for(i = 0 ; i < w->ep_cache_sz ; i++) {
if(!w->ep_cache[i]) {
w->ep_cache[i] = p;
break;
}
}
JK_LEAVE_CS(&w->cs, rc);
if(i < w->ep_cache_sz) {
return JK_TRUE;
}
}
}
}
close_endpoint(p);
*e = NULL;
return JK_TRUE;
}
jk_log(l,
JK_LOG_ERROR,
"In jk_endpoint_t::done, NULL parameters\n");
return JK_FALSE;
}
/*
* send request to Tomcat via Ajp13
* - first try to find reuseable socket
* - if no one available, try to connect
* - send request, but send must be see as asynchronous,
* since send() call will return noerror about 95% of time
* Hopefully we'll get more information on next read.
*
* nb: reqmsg is the original request msg buffer
* repmsg is the reply msg buffer which could be scratched
*/
static int send_request(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l,
ajp13_endpoint_t *p,
ajp13_operation_t *op)
{
/* Up to now, we can recover */
op->recoverable = JK_TRUE;
/*
* First try to reuse open connections...
*/
while((p->sd > 0) && !connection_tcp_send_message(p, op->request, l)) {
jk_log(l, JK_LOG_ERROR, "Error sending request try another pooled connection\n");
jk_close_socket(p->sd);
p->sd = -1;
reuse_connection(p, l);
}
/*
* If we failed to reuse a connection, try to reconnect.
*/
if(p->sd < 0) {
connect_to_tomcat(p, l);
if(p->sd >= 0) {
/*
* After we are connected, each error that we are going to
* have is probably unrecoverable
*/
if(!connection_tcp_send_message(p, op->request, l)) {
jk_log(l, JK_LOG_ERROR, "Error sending request on a fresh connection\n");
return JK_FALSE;
}
} else {
jk_log(l, JK_LOG_ERROR, "Error connecting to the Tomcat process.\n");
return JK_FALSE;
}
}
/*
* From now on an error means that we have an internal server error
* or Tomcat crashed. In any case we cannot recover this.
*/
jk_log(l, JK_LOG_DEBUG, "send_request 2: request body to send %d - request body to resend %d\n",
p->left_bytes_to_send, jk_b_get_len(op->reply) - AJP13_HEADER_LEN);
/*
* POST recovery job is done here.
* It's not very fine to have posted data in reply but that's the only easy
* way to do that for now. Sharing the reply is really a bad solution but
* it will works for POST DATA less than 8k.
* We send here the first part of data which was sent previously to the
* remote Tomcat
*/
if(jk_b_get_len(op->reply) > AJP13_HEADER_LEN) {
if(!connection_tcp_send_message(p, op->reply, l)) {
jk_log(l, JK_LOG_ERROR, "Error resending request body\n");
return JK_FALSE;
}
}
else
{
/* We never sent any POST data and we check it we have to send at
* least of block of data (max 8k). These data will be kept in reply
* for resend if the remote Tomcat is down, a fact we will learn only
* doing a read (not yet)
*/
if(p->left_bytes_to_send > 0) {
unsigned len = p->left_bytes_to_send;
if(len > MAX_SEND_BODY_SZ)
len = MAX_SEND_BODY_SZ;
if(!read_into_msg_buff(p, s, op->reply, l, len)) {
/* the browser stop sending data, no need to recover */
op->recoverable = JK_FALSE;
return JK_FALSE;
}
s->content_read = len;
if(!connection_tcp_send_message(p, op->reply, l)) {
jk_log(l, JK_LOG_ERROR, "Error sending request body\n");
return JK_FALSE;
}
}
}
return (JK_TRUE);
}
/*
* get replies from Tomcat via Ajp13
* We will know only at read time if the remote host closed
* the connection (half-closed state - FIN-WAIT2). In that case
* we must close our side of the socket and abort emission.
* We will need another connection to send the request
* There is need of refactoring here since we mix
* reply reception (tomcat -> apache) and request send (apache -> tomcat)
* and everything using the same buffer (repmsg)
* ajp13 is async but handling read/send this way prevent nice recovery
* In fact if tomcat link is broken during upload (browser -> apache -> tomcat)
* we'll loose data and we'll have to abort the whole request.
*/
static int get_reply(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l,
ajp13_endpoint_t *p,
ajp13_operation_t *op)
{
/* Start read all reply message */
while(1) {
int rc = 0;
if(!connection_tcp_get_message(p, op->reply, l)) {
jk_log(l, JK_LOG_ERROR, "Error reading reply\n");
/* we just can't recover, unset recover flag */
return JK_FALSE;
}
rc = ajp13_process_callback(op->reply, p, s, l);
/* no more data to be sent, fine we have finish here */
if(JK_AJP13_END_RESPONSE == rc)
return JK_TRUE;
else if(JK_AJP13_HAS_RESPONSE == rc) {
/*
* in upload-mode there is no second chance since
* we may have allready send part of uploaded data
* to Tomcat.
* In this case if Tomcat connection is broken we must
* abort request and indicate error.
* A possible work-around could be to store the uploaded
* data to file and replay for it
*/
op->recoverable = JK_FALSE;
rc = connection_tcp_send_message(p, op->reply, l);
if (rc < 0) {
jk_log(l, JK_LOG_ERROR, "Error sending request data %d\n", rc);
return JK_FALSE;
}
} else if(rc < 0) {
return (JK_FALSE); /* XXX error */
}
}
}
#define JK_RETRIES 3
/*
* service is now splitted in send_request and get_reply
* much more easier to do errors recovery
*/
static int JK_METHOD service(jk_endpoint_t *e,
jk_ws_service_t *s,
jk_logger_t *l,
int *is_recoverable_error)
{
int i;
ajp13_operation_t oper;
ajp13_operation_t *op = &oper;
jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::service\n");
if(e && e->endpoint_private && s && is_recoverable_error) {
ajp13_endpoint_t *p = e->endpoint_private;
op->request = jk_b_new(&(p->pool));
jk_b_set_buffer_size(op->request, DEF_BUFFER_SZ);
jk_b_reset(op->request);
op->reply = jk_b_new(&(p->pool));
jk_b_set_buffer_size(op->reply, DEF_BUFFER_SZ);
jk_b_reset(op->reply);
op->recoverable = JK_TRUE;
op->uploadfd = -1; /* not yet used, later ;) */
p->left_bytes_to_send = s->content_length;
p->reuse = JK_FALSE;
*is_recoverable_error = JK_TRUE;
/*
* We get here initial request (in reqmsg)
*/
if(!ajp13_marshal_into_msgb(op->request, s, l)) {
*is_recoverable_error = JK_FALSE;
return JK_FALSE;
}
/*
* JK_RETRIES could be replaced by the number of workers in
* a load-balancing configuration
*/
for (i = 0; i < JK_RETRIES; i++)
{
/*
* We're using reqmsg which hold initial request
* if Tomcat is stopped or restarted, we will pass reqmsg
* to next valid tomcat.
*/
if (send_request(e, s, l, p, op)) {
/* If we have the no recoverable error, it's probably because the sender (browser)
* stop sending data before the end (certainly in a big post)
*/
if (! op->recoverable) {
*is_recoverable_error = JK_FALSE;
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, send_request failed without recovery in send loop %d\n", i);
return JK_FALSE;
}
/* Up to there we can recover */
*is_recoverable_error = JK_TRUE;
op->recoverable = JK_TRUE;
if (get_reply(e, s, l, p, op))
return (JK_TRUE);
/* if we can't get reply, check if no recover flag was set
* if is_recoverable_error is cleared, we have started received
* upload data and we must consider that operation is no more recoverable
*/
if (! op->recoverable) {
*is_recoverable_error = JK_FALSE;
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, get_reply failed without recovery in send loop %d\n", i);
return JK_FALSE;
}
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, get_reply failed in send loop %d\n", i);
}
else
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, send_request failed in send loop %d\n", i);
jk_close_socket(p->sd);
p->sd = -1;
reuse_connection(p, l);
}
} else {
jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, NULL parameters\n");
}
return JK_FALSE;
}
static int JK_METHOD get_endpoint(jk_worker_t *pThis,
jk_endpoint_t **pend,
jk_logger_t *l)
{
jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint\n");
if(pThis && pThis->worker_private && pend) {
ajp13_worker_t *p = pThis->worker_private;
ajp13_endpoint_t *ep = NULL;
if(p->ep_cache_sz) {
int rc;
JK_ENTER_CS(&p->cs, rc);
if(rc) {
unsigned i;
for(i = 0 ; i < p->ep_cache_sz ; i++) {
if(p->ep_cache[i]) {
ep = p->ep_cache[i];
p->ep_cache[i] = NULL;
break;
}
}
JK_LEAVE_CS(&p->cs, rc);
if(ep) {
*pend = &ep->endpoint;
return JK_TRUE;
}
}
}
ep = (ajp13_endpoint_t *)malloc(sizeof(ajp13_endpoint_t));
if(ep) {
ep->sd = -1;
ep->reuse = JK_FALSE;
jk_open_pool(&ep->pool, ep->buf, sizeof(ep->buf));
ep->worker = pThis->worker_private;
ep->endpoint.endpoint_private = ep;
ep->endpoint.service = service;
ep->endpoint.done = done;
*pend = &ep->endpoint;
return JK_TRUE;
}
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, malloc failed\n");
} else {
jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL parameters\n");
}
return JK_FALSE;
}
int JK_METHOD ajp13_worker_factory(jk_worker_t **w,
const char *name,
jk_logger_t *l)
{
ajp13_worker_t *private_data =
(ajp13_worker_t *)malloc(sizeof(ajp13_worker_t));
jk_log(l,
JK_LOG_DEBUG,
"Into ajp13_worker_factory\n");
if(NULL == name || NULL == w) {
jk_log(l,
JK_LOG_ERROR,
"In ajp13_worker_factory, NULL parameters\n");
return JK_FALSE;
}
if(!private_data) {
jk_log(l, JK_LOG_ERROR, "In ajp13_worker_factory, NULL parameters\n");
return JK_FALSE;
}
private_data->name = strdup(name);
if(!private_data->name) {
free(private_data);
jk_log(l, JK_LOG_ERROR, "In ajp13_worker_factory, malloc failed\n");
return JK_FALSE;
}
private_data->ep_cache_sz = 0;
private_data->ep_cache = NULL;
private_data->connect_retry_attempts = DEF_RETRY_ATTEMPTS;
private_data->worker.worker_private = private_data;
private_data->worker.validate = validate;
private_data->worker.init = init;
private_data->worker.get_endpoint = get_endpoint;
private_data->worker.destroy = destroy;
*w = &private_data->worker;
return JK_TRUE;
}
1.1 jakarta-tomcat/proposals/web-connector/native/common/jk_ajp13_worker.h
Index: jk_ajp13_worker.h
===================================================================
/*
* Copyright (c) 1997-1999 The Java Apache Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* 4. The names "Apache JServ", "Apache JServ Servlet Engine" and
* "Java Apache Project" must not be used to endorse or promote products
* derived from this software without prior written permission.
*
* 5. Products derived from this software may not be called "Apache JServ"
* nor may "Apache" nor "Apache JServ" appear in their names without
* prior written permission of the Java Apache Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Java Apache
* Project for use in the Apache JServ servlet engine project
* <http://java.apache.org/>."
*
* THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Java Apache Group. For more information
* on the Java Apache Project and the Apache JServ Servlet Engine project,
* please see <http://java.apache.org/>.
*
*/
/***************************************************************************
* Description: ajpv1.3 worker header file *
* Author: Gal Shachor <sh...@il.ibm.com> *
* Version: $Revision: 1.1 $ *
***************************************************************************/
#ifndef JK_AJP13_WORKER_H
#define JK_AJP13_WORKER_H
#include "jk_logger.h"
#include "jk_service.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define JK_AJP13_WORKER_NAME ("ajp13")
int JK_METHOD ajp13_worker_factory(jk_worker_t **w,
const char *name,
jk_logger_t *l);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* JK_AJP13_WORKER_H */