From 947885f48cef4aeb976ab2d6176c3bfd5d18847b Mon Sep 17 00:00:00 2001 From: erickson Date: Fri, 24 Feb 2006 23:17:05 +0000 Subject: [PATCH] re-vamped gateway to make it more stable and faster. also moved the apachetools stuff into the opensrf tree since it's all pure opensrf and the gateway made good use of it. will remove the ils_gateway module shortly git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@642 9efc2488-bf62-4759-914b-345cdb29e865 --- src/gateway/Makefile | 14 ++- src/gateway/apachetools.c | 129 +++++++++++++++++++++++ src/gateway/apachetools.h | 48 +++++++++ src/gateway/osrf_json_gateway.c | 181 ++++++++++++++++++++++++++++++++ 4 files changed, 370 insertions(+), 2 deletions(-) create mode 100644 src/gateway/apachetools.c create mode 100644 src/gateway/apachetools.h create mode 100644 src/gateway/osrf_json_gateway.c diff --git a/src/gateway/Makefile b/src/gateway/Makefile index 96b5eed..05b9ad3 100644 --- a/src/gateway/Makefile +++ b/src/gateway/Makefile @@ -1,15 +1,25 @@ CCFLAGS += -DASSUME_STATELESS LDLIBS += -lobjson -lxml2 -lopensrf -all: mod_ils_gateway.so +all: mod_ils_gateway.so osrf_json_gateway.so copy install: $(APXS2) -i -a -n ils_gateway mod_ils_gateway.so + $(APXS2) -i -a -n osrf_json_gateway osrf_json_gateway.so + cp apachetools.h $(INCLUDEDIR)/opensrf/ +mod_ils_gateway.o: mod_ils_gateway.h mod_ils_gateway.c mod_ils_gateway.so: mod_ils_gateway.o $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared -W1 mod_ils_gateway.o -o mod_ils_gateway.so -mod_ils_gateway.o: mod_ils_gateway.h mod_ils_gateway.c +copy: + cp apachetools.h $(TMPDIR) + +apachetools.o: apachetools.h apachetools.c +osrf_json_gateway.o: osrf_json_gateway.c +osrf_json_gateway.so: osrf_json_gateway.o apachetools.o + $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared -W1 apachetools.o osrf_json_gateway.o -o osrf_json_gateway.so + clean: /bin/rm -f *.o *.so diff --git a/src/gateway/apachetools.c b/src/gateway/apachetools.c new file mode 100644 index 0000000..204a192 --- /dev/null +++ b/src/gateway/apachetools.c @@ -0,0 +1,129 @@ +#include "apachetools.h" + +string_array* apacheParseParms(request_rec* r) { + + if( r == NULL ) return NULL; + + char* arg = r->args; /* url query string */ + apr_pool_t *p = r->pool; /* memory pool */ + string_array* sarray = init_string_array(12); /* method parameters */ + + growing_buffer* buffer = NULL; /* POST data */ + growing_buffer* tmp_buf = NULL; /* temp buffer */ + + char* key = NULL; /* query item name */ + char* val = NULL; /* query item value */ + + + /* gather the post args and append them to the url query string */ + if( !strcmp(r->method,"POST") ) { + + ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); + + if(ap_should_client_block(r)) { + + char body[1025]; + memset(body,0,1025); + buffer = buffer_init(1025); + + while(ap_get_client_block(r, body, 1024)) { + buffer_add( buffer, body ); + memset(body,0,1025); + } + + if(arg && arg[0]) { + + tmp_buf = buffer_init(1024); + buffer_add(tmp_buf,arg); + buffer_add(tmp_buf,buffer->buf); + arg = (char*) apr_pstrdup(p, tmp_buf->buf); + buffer_free(tmp_buf); + + } else { + arg = (char*) apr_pstrdup(p, buffer->buf); + } + + buffer_free(buffer); + } + } + + + if( ! arg || !arg[0] ) { /* we received no request */ + return NULL; + } + + + while( arg && (val = ap_getword(p, (const char**) &arg, '&'))) { + + key = ap_getword(r->pool, (const char**) &val, '='); + if(!key || !key[0]) + break; + + ap_unescape_url((char*)key); + ap_unescape_url((char*)val); + + string_array_add(sarray, key); + string_array_add(sarray, val); + + } + + return sarray; + +} + + + +string_array* apacheGetParamKeys(string_array* params) { + if(params == NULL) return NULL; + string_array* sarray = init_string_array(12); + int i; + for( i = 0; i < params->size; i++ ) + string_array_add(sarray, string_array_get_string(params, i++)); + return sarray; +} + +string_array* apacheGetParamValues(string_array* params, char* key) { + + if(params == NULL || key == NULL) return NULL; + string_array* sarray = init_string_array(12); + + int i; + for( i = 0; i < params->size; i++ ) { + char* nkey = string_array_get_string(params, i++); + if(key && !strcmp(nkey, key)) + string_array_add(sarray, string_array_get_string(params, i)); + } + return sarray; +} + + +char* apacheGetFirstParamValue(string_array* params, char* key) { + if(params == NULL || key == NULL) return NULL; + + int i; + for( i = 0; i < params->size; i++ ) { + char* nkey = string_array_get_string(params, i++); + if(key && !strcmp(nkey, key)) + return strdup(string_array_get_string(params, i)); + } + + return NULL; +} + + +int apacheDebug( char* msg, ... ) { + VA_LIST_TO_STRING(msg); + fprintf(stderr, "%s\n", VA_BUF); + fflush(stderr); + return 0; +} + + +int apacheError( char* msg, ... ) { + VA_LIST_TO_STRING(msg); + fprintf(stderr, "%s\n", VA_BUF); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; +} + + diff --git a/src/gateway/apachetools.h b/src/gateway/apachetools.h new file mode 100644 index 0000000..2669468 --- /dev/null +++ b/src/gateway/apachetools.h @@ -0,0 +1,48 @@ +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" +#include "apr_compat.h" +#include "apr_strings.h" +#include "apr_reslist.h" +#include "http_log.h" + + +#include "opensrf/string_array.h" +#include "opensrf/utils.h" +#include "opensrf/utils.h" + +#ifndef APACHE_TOOLS_H +#define APACHE_TOOLS_H + + +/* parses apache URL params (GET and POST). + Returns a string_array of the form [ key, val, key, val, ...] + Returns NULL if there are no params */ +string_array* apacheParseParms(request_rec* r); + +/* provide the params string array, and this will generate a + string of array of param keys + the returned string_array most be freed by the caller + */ +string_array* apacheGetParamKeys(string_array* params); + +/* provide the params string array and a key name, and + this will provide the value found for that key + the returned string_array most be freed by the caller + */ +string_array* apacheGetParamValues(string_array* params, char* key); + +/* returns the first value found for the given param. + char* must be freed by the caller */ +char* apacheGetFirstParamValue(string_array* params, char* key); + +/* Writes msg to stderr, flushes stderr, and returns 0 */ +int apacheDebug( char* msg, ... ); + +/* Writes to stderr, flushe stderr, and returns HTTP_INTERNAL_SERVER_ERROR; + */ +int apacheError( char* msg, ... ); + + +#endif diff --git a/src/gateway/osrf_json_gateway.c b/src/gateway/osrf_json_gateway.c new file mode 100644 index 0000000..cf79675 --- /dev/null +++ b/src/gateway/osrf_json_gateway.c @@ -0,0 +1,181 @@ +#include "apachetools.h" +#include "opensrf/osrf_app_session.h" +#include "opensrf/osrf_system.h" +#include "objson/object.h" + +#define MODULE_NAME "osrf_json_gateway_module" +#define GATEWAY_CONFIG "OSRFGatewayConfig" +#define CONFIG_CONTEXT "gateway" + +#define GATEWAY_DEFAULT_CONFIG "/openils/conf/opensrf_core.xml" + + +/* our config structure */ +typedef struct { + char* configfile; /* our bootstrap config file */ +} osrf_json_gateway_config; + +module AP_MODULE_DECLARE_DATA osrf_json_gateway_module; + +char* osrf_json_gateway_config_file = NULL; +int bootstrapped = 0; + +static const char* osrf_json_gateway_set_config(cmd_parms *parms, void *config, const char *arg) { + osrf_json_gateway_config *cfg; + cfg = ap_get_module_config(parms->server->module_config, &osrf_json_gateway_module); + cfg->configfile = (char*) arg; + osrf_json_gateway_config_file = (char*) arg; + return NULL; +} + +/* tell apache about our commands */ +static const command_rec osrf_json_gateway_cmds[] = { + AP_INIT_TAKE1( GATEWAY_CONFIG, osrf_json_gateway_set_config, + NULL, RSRC_CONF, "osrf json gateway config file"), + {NULL} +}; + +/* build the config object */ +static void* osrf_json_gateway_create_config( apr_pool_t* p, server_rec* s) { + osrf_json_gateway_config* cfg = (osrf_json_gateway_config*) + apr_palloc(p, sizeof(osrf_json_gateway_config)); + cfg->configfile = GATEWAY_DEFAULT_CONFIG; + return (void*) cfg; +} + + +static void osrf_json_gateway_child_init(apr_pool_t *p, server_rec *s) { + + char* cfg = osrf_json_gateway_config_file; + if( ! osrf_system_bootstrap_client( cfg, CONFIG_CONTEXT) ) { + ap_log_error( APLOG_MARK, APLOG_ERR, 0, s, "Unable to Bootstrap OpenSRF Client.."); + return; + } + bootstrapped = 1; + ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "Bootstrapping OpenSRF Client.."); +} + +static int osrf_json_gateway_method_handler (request_rec *r) { + + /* make sure we're needed first thing*/ + if (strcmp(r->handler, MODULE_NAME )) return DECLINED; + + /* verify we are connected */ + if( !bootstrapped || !osrf_system_get_transport_client()) { + ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, r, "Cannot process request " + "because the OpenSRF JSON gateway has not been bootstrapped..."); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + osrfLogSetAppname("osrf_json_gw"); + + char* service = NULL; /* service to connect to */ + char* method = NULL; /* method to perform */ + int api_level = 1; /* request api level */ + + ap_set_content_type(r, "text/plain"); + + r->allowed |= (AP_METHOD_BIT << M_GET); + r->allowed |= (AP_METHOD_BIT << M_POST); + + string_array* mparams = NULL; + string_array* params = apacheParseParms(r); /* free me */ + service = apacheGetFirstParamValue( params, "service" ); + method = apacheGetFirstParamValue( params, "method" ); + mparams = apacheGetParamValues( params, "param" ); /* free me */ + + if( service && method ) { + + osrfLogInfo( OSRF_LOG_MARK, "service=%s, method=%s", service, method ); + osrfAppSession* session = osrf_app_client_session_init(service); + int req_id = osrf_app_session_make_req( session, NULL, method, api_level, mparams ); + osrf_message* omsg = NULL; + + int statuscode = 200; + + /* kick off the object */ + ap_rputs("{\"payload\":[", r); + + int morethan1 = 0; + char* statusname = NULL; + char* statustext = NULL; + + while((omsg = osrfAppSessionRequestRecv( session, req_id, 60 ))) { + + statuscode = omsg->status_code; + jsonObject* res; + + if( ( res = osrfMessageGetResult(omsg)) ) { + + char* json = jsonObjectToJSON( res ); + if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */ + ap_rputs(json, r); + free(json); + morethan1 = 1; + + } else { + + if( statuscode > 299 ) { /* the request returned a low level error */ + statusname = omsg->status_name ? strdup(omsg->status_name) : strdup("Unknown Error"); + statustext = omsg->status_text ? strdup(omsg->status_text) : strdup("No Error Message"); + osrfLogError( OSRF_LOG_MARK, "Gateway received error: %s", statustext ); + } + } + + osrf_message_free(omsg); + if(statusname) break; + } + + ap_rputs("]",r); /* finish off the payload array */ + + if(statusname) { + + /* add a debug field if the request died */ + ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, + "OpenSRF JSON Request returned error: %s -> %s", statusname, statustext ); + int l = strlen(statusname) + strlen(statustext) + 24; + char buf[l]; + bzero(buf,l); + snprintf( buf, l, ",\"debug\":\"%s : %s\"", statusname, statustext ); + ap_rputs(buf, r); + + free(statusname); + free(statustext); + } + + /* insert the statu code */ + char buf[24]; + bzero(buf,24); + snprintf(buf, 24, ",\"status\":%d", statuscode ); + ap_rputs( buf, r ); + + ap_rputs( "}", r ); /* finish off the object */ + osrf_app_session_destroy(session); + } + + string_array_destroy(params); + string_array_destroy(mparams); + + return OK; +} + +static void osrf_json_gateway_register_hooks (apr_pool_t *p) { + ap_hook_handler(osrf_json_gateway_method_handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(osrf_json_gateway_child_init,NULL,NULL,APR_HOOK_MIDDLE); +} + + +module AP_MODULE_DECLARE_DATA osrf_json_gateway_module = { + STANDARD20_MODULE_STUFF, + NULL, + NULL, + osrf_json_gateway_create_config, + NULL, + osrf_json_gateway_cmds, + osrf_json_gateway_register_hooks, +}; + + + + -- 2.43.2