From e6ce5c1c95e54de3f550a96a0d52b4bb67a03f7e Mon Sep 17 00:00:00 2001 From: miker Date: Thu, 2 Aug 2007 02:49:53 +0000 Subject: [PATCH] initial sender_locale support ... probably going to break stuff; also, patch from Scott McKellar to define some undefined behavior in an snprintf call git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1066 9efc2488-bf62-4759-914b-345cdb29e865 --- include/opensrf/osrf_app_session.h | 14 +++++ include/opensrf/osrf_message.h | 21 ++++++++ src/gateway/osrf_json_gateway.c | 49 ++++++++++++++++- src/libopensrf/opensrf.c | 2 - src/libopensrf/osrf_app_session.c | 27 ++++++++-- src/libopensrf/osrf_application.c | 35 ++++++------- src/libopensrf/osrf_message.c | 52 ++++++++++++++----- src/perlmods/OpenSRF/AppSession.pm | 22 ++++++-- .../OpenSRF/DomainObject/oilsMessage.pm | 18 +++++++ 9 files changed, 197 insertions(+), 43 deletions(-) diff --git a/include/opensrf/osrf_app_session.h b/include/opensrf/osrf_app_session.h index 3cdbcb6..561454e 100644 --- a/include/opensrf/osrf_app_session.h +++ b/include/opensrf/osrf_app_session.h @@ -75,6 +75,9 @@ struct osrf_app_session_struct { /** SERVER or CLIENT */ enum OSRF_SESSION_TYPE type; + /** the current locale for this session **/ + char* session_locale; + /* let the user use the session to store their own session data */ void* userData; @@ -99,6 +102,9 @@ osrf_app_session* osrf_app_client_session_init( char* remote_service ); osrf_app_session* osrf_app_server_session_init( char* session_id, char* our_app, char* remote_id ); +/** sets the default locale for a session **/ +char* osrf_app_session_set_locale( osrf_app_session*, const char* ); + /** returns a session from the global session hash */ osrf_app_session* osrf_app_session_find_session( char* session_id ); @@ -114,6 +120,14 @@ int osrf_app_session_make_req( osrf_app_session* session, jsonObject* params, char* method_name, int protocol, string_array* param_strings); +int osrfAppSessionMakeLocaleRequest( + osrf_app_session* session, jsonObject* params, + char* method_name, int protocol, string_array* param_strings, char* locale); + +int osrf_app_session_make_locale_req( + osrf_app_session* session, jsonObject* params, + char* method_name, int protocol, string_array* param_strings, char* locale); + /** Sets the given request to complete state */ void osrf_app_session_set_complete( osrf_app_session* session, int request_id ); diff --git a/include/opensrf/osrf_message.h b/include/opensrf/osrf_message.h index ca79082..e8d5b75 100644 --- a/include/opensrf/osrf_message.h +++ b/include/opensrf/osrf_message.h @@ -75,10 +75,31 @@ struct osrf_message_struct { char* full_param_string; + /* magical LOCALE hint */ + char* sender_locale; + + /* timezone offset from GMT of sender, in seconds */ + int sender_tz_offset; + }; typedef struct osrf_message_struct osrf_message; typedef struct osrf_message_struct osrfMessage; +/* Set the locale hint for this message. + default_locale is used if not set. + Returns NULL if msg or locale is not set, char* to msg->sender_locale on success. +*/ +char* osrf_message_set_locale( osrf_message* msg, const char* locale ); + +/* Set the default locale hint to be used for future outgoing messages. + Returns NULL if locale is NULL, const char* to default_locale otherwise. +*/ +const char* osrf_message_set_default_locale( const char* locale ); + +/* Get the current locale hint -- either the default or most recently received locale. + Returns const char* to current_locale. +*/ +const char* osrf_message_get_current_locale(void); osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ); //void osrf_message_set_request_info( osrf_message*, char* param_name, json* params ); diff --git a/src/gateway/osrf_json_gateway.c b/src/gateway/osrf_json_gateway.c index 9dfa5d3..49c0f1a 100644 --- a/src/gateway/osrf_json_gateway.c +++ b/src/gateway/osrf_json_gateway.c @@ -8,10 +8,12 @@ #include #include #include +#include #define MODULE_NAME "osrf_json_gateway_module" #define GATEWAY_CONFIG "OSRFGatewayConfig" +#define DEFAULT_LOCALE "OSRFDefaultLocale" #define CONFIG_CONTEXT "gateway" #define JSON_PROTOCOL "OSRFGatewayLegacyJSON" #define GATEWAY_USE_LEGACY_JSON 1 @@ -31,11 +33,17 @@ typedef struct { module AP_MODULE_DECLARE_DATA osrf_json_gateway_module; +char* osrf_json_default_locale = "en-US"; char* osrf_json_gateway_config_file = NULL; int bootstrapped = 0; int numserved = 0; osrfStringArray* allowedServices = NULL; +static const char* osrf_json_gateway_set_default_locale(cmd_parms *parms, void *config, const char *arg) { + osrf_json_default_locale = (char*) arg; + return NULL; +} + 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); @@ -54,6 +62,8 @@ static const char* osrf_json_gateway_set_json_proto(cmd_parms *parms, void *conf 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"), + AP_INIT_TAKE1( DEFAULT_LOCALE, osrf_json_gateway_set_default_locale, + NULL, RSRC_CONF, "osrf json gateway default locale"), AP_INIT_TAKE1( JSON_PROTOCOL, osrf_json_gateway_set_json_proto, NULL, ACCESS_CONF, "osrf json gateway config file"), {NULL} @@ -137,6 +147,8 @@ static int osrf_json_gateway_method_handler (request_rec *r) { osrfLogSetAppname("osrf_json_gw"); + char* osrf_locale = NULL; + char* param_locale = NULL; /* locale for this call */ char* service = NULL; /* service to connect to */ char* method = NULL; /* method to perform */ char* format = NULL; /* method to perform */ @@ -151,6 +163,7 @@ static int osrf_json_gateway_method_handler (request_rec *r) { osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: parsing URL params"); string_array* mparams = NULL; string_array* params = apacheParseParms(r); /* free me */ + param_locale = apacheGetFirstParamValue( params, "locale" ); service = apacheGetFirstParamValue( params, "service" ); method = apacheGetFirstParamValue( params, "method" ); format = apacheGetFirstParamValue( params, "format" ); @@ -184,6 +197,38 @@ static int osrf_json_gateway_method_handler (request_rec *r) { int ret = OK; + /* ----------------------------------------------------------------- */ + /* Grab the requested locale using the Accept-Language header*/ + + + if ( !param_locale ) { + if ( apr_table_get(r->headers_in, "X-OpenSRF-Language") ) { + param_locale = strdup( apr_table_get(r->headers_in, "X-OpenSRF-Language") ); + } else if ( apr_table_get(r->headers_in, "Accept-Language") ) { + param_locale = strdup( apr_table_get(r->headers_in, "Accept-Language") ); + } + } + + + if (param_locale) { + growing_buffer* osrf_locale_buf = buffer_init(16); + if (index(param_locale, ',')) { + int ind = index(param_locale, ',') - param_locale; + int i; + for ( i = 0; i < ind - 1 && i < 128; i++ ) + buffer_add_char( osrf_locale_buf, param_locale[i] ); + } else { + buffer_add( osrf_locale_buf, param_locale ); + } + + free(param_locale); + osrf_locale = buffer_release( osrf_locale_buf ); + } else { + osrf_locale = strdup( osrf_json_default_locale ); + } + /* ----------------------------------------------------------------- */ + + if(!(service && method) || !osrfStringArrayContains(allowedServices, service)) { @@ -205,6 +250,7 @@ static int osrf_json_gateway_method_handler (request_rec *r) { */ osrfAppSession* session = osrf_app_client_session_init(service); + osrf_app_session_set_locale(session, osrf_locale); double starttime = get_timestamp_millis(); int req_id = -1; @@ -294,7 +340,6 @@ static int osrf_json_gateway_method_handler (request_rec *r) { if (isXML) { output = jsonObjectToXML( res ); } else { - //output = jsonObjectToJSON( res ); output = jsonToStringFunc( res ); if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */ } @@ -342,7 +387,6 @@ static int osrf_json_gateway_method_handler (request_rec *r) { snprintf(bb, l, "%s : %s", statusname, statustext); jsonObject* tmp = jsonNewObject(bb); char* j = jsonToStringFunc(tmp); - //char* j = jsonObjectToJSON(tmp); snprintf( buf, l, ",\"debug\": %s", j); free(j); jsonObjectFree(tmp); @@ -374,6 +418,7 @@ static int osrf_json_gateway_method_handler (request_rec *r) { } osrfLogInfo(OSRF_LOG_MARK, "Completed processing service=%s, method=%s", service, method); + free(osrf_locale); string_array_destroy(params); string_array_destroy(mparams); diff --git a/src/libopensrf/opensrf.c b/src/libopensrf/opensrf.c index 3b6f6fd..e7215d2 100644 --- a/src/libopensrf/opensrf.c +++ b/src/libopensrf/opensrf.c @@ -1,6 +1,4 @@ #include -//#include -//#include int main( int argc, char* argv[] ) { diff --git a/src/libopensrf/osrf_app_session.c b/src/libopensrf/osrf_app_session.c index ef16ce5..308048d 100644 --- a/src/libopensrf/osrf_app_session.c +++ b/src/libopensrf/osrf_app_session.c @@ -204,6 +204,11 @@ osrf_app_session* osrfAppSessionClientInit( char* remote_service ) { osrf_app_session* osrf_app_client_session_init( char* remote_service ) { + if (!remote_service) { + osrfLogWarning( OSRF_LOG_MARK, "No remote service specified in osrf_app_client_session_init"); + return NULL; + } + osrf_app_session* session = safe_malloc(sizeof(osrf_app_session)); session->transport_handle = osrf_system_get_transport_client(); @@ -213,14 +218,28 @@ osrf_app_session* osrf_app_client_session_init( char* remote_service ) { return NULL; } - char target_buf[512]; - target_buf[ 0 ] = '\0'; - osrfStringArray* arr = osrfNewStringArray(8); osrfConfigGetValueList(NULL, arr, "/domains/domain"); char* domain = osrfStringArrayGetString(arr, 0); + + if (!domain) { + osrfLogWarning( OSRF_LOG_MARK, "No domains specified in the OpenSRF config file"); + free( session ); + osrfStringArrayFree(arr); + return NULL; + } + char* router_name = osrfConfigGetValue(NULL, "/router_name"); - + if (!router_name) { + osrfLogWarning( OSRF_LOG_MARK, "No router name specified in the OpenSRF config file"); + free( session ); + osrfStringArrayFree(arr); + return NULL; + } + + char target_buf[512]; + target_buf[ 0 ] = '\0'; + int len = snprintf( target_buf, 512, "%s@%s/%s", router_name ? router_name : "(null)", domain ? domain : "(null)", diff --git a/src/libopensrf/osrf_application.c b/src/libopensrf/osrf_application.c index b69659f..c70d446 100644 --- a/src/libopensrf/osrf_application.c +++ b/src/libopensrf/osrf_application.c @@ -12,7 +12,7 @@ int osrfAppRegisterApplication( char* appName, char* soFile ) { osrfApplication* app = safe_malloc(sizeof(osrfApplication)); app->handle = dlopen (soFile, RTLD_NOW); - app->onExit = NULL; + app->onExit = NULL; if(!app->handle) { osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() ); @@ -51,28 +51,27 @@ int osrfAppRegisterApplication( char* appName, char* soFile ) { osrfLogSetAppname(appName); - osrfAppSetOnExit(app, appName); + osrfAppSetOnExit(app, appName); return 0; } void osrfAppSetOnExit(osrfApplication* app, char* appName) { - if(!(app && appName)) return; + if(!(app && appName)) return; /* see if we can run the initialize method */ - char* error; + char* error; void (*onExit) (void); *(void **) (&onExit) = dlsym(app->handle, "osrfAppChildExit"); if( (error = dlerror()) != NULL ) { - osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName); - return; - } + osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName); + return; + } - osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName); - app->onExit = (*onExit); - //if( (ret = (*onExit)()) ) { + osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName); + app->onExit = (*onExit); } @@ -102,14 +101,14 @@ int osrfAppRunChildInit(char* appname) { void osrfAppRunExitCode() { - osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash); - osrfApplication* app; - while( (app = osrfHashIteratorNext(itr)) ) { - if( app->onExit ) { - osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current); - app->onExit(); - } - } + osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash); + osrfApplication* app; + while( (app = osrfHashIteratorNext(itr)) ) { + if( app->onExit ) { + osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current); + app->onExit(); + } + } } diff --git a/src/libopensrf/osrf_message.c b/src/libopensrf/osrf_message.c index 313216a..57d2bd5 100644 --- a/src/libopensrf/osrf_message.c +++ b/src/libopensrf/osrf_message.c @@ -1,5 +1,8 @@ #include +static char default_locale[17] = "en-US\0\0\0\0\0\0\0\0\0\0\0\0"; +static char* current_locale = default_locale; + osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ) { osrf_message* msg = (osrf_message*) safe_malloc(sizeof(osrf_message)); @@ -10,11 +13,30 @@ osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protoco msg->is_exception = 0; msg->_params = NULL; msg->_result_content = NULL; + msg->sender_locale = NULL; return msg; } +const char* osrf_message_get_last_locale() { + return current_locale; +} + +char* osrf_message_set_locale( osrf_message* msg, const char* locale ) { + if( msg == NULL || locale == NULL ) return NULL; + return msg->sender_locale = strdup( locale ); +} + +const char* osrf_message_set_default_locale( const char* locale ) { + if( locale == NULL ) return NULL; + if( strlen(locale) > 16 ) return NULL; + + memcpy( default_locale, locale, strlen(locale) ); + default_locale[strlen(locale)] = '\0'; + return (const char*) default_locale; +} + void osrf_message_set_method( osrf_message* msg, char* method_name ) { if( msg == NULL || method_name == NULL ) return; msg->method_name = strdup( method_name ); @@ -101,6 +123,9 @@ void osrf_message_free( osrf_message* msg ) { if( msg->method_name != NULL ) free(msg->method_name); + if( msg->sender_locale != NULL ) + free(msg->sender_locale); + if( msg->_params != NULL ) jsonObjectFree(msg->_params); @@ -156,6 +181,14 @@ jsonObject* osrfMessageToJSON( osrfMessage* msg ) { INT_TO_STRING(msg->thread_trace); jsonObjectSetKey(json, "threadTrace", jsonNewObject(INTSTR)); + if (msg->sender_locale != NULL) { + jsonObjectSetKey(json, "locale", jsonNewObject(msg->sender_locale)); + } else if (current_locale != NULL) { + jsonObjectSetKey(json, "locale", jsonNewObject(current_locale)); + } else { + jsonObjectSetKey(json, "locale", jsonNewObject(default_locale)); + } + switch(msg->m_type) { case CONNECT: @@ -249,14 +282,14 @@ int osrf_message_deserialize(char* string, osrf_message* msgs[], int count) { new_msg->thread_trace = atoi(tt); free(tt); } - /* - if(tmp->type == JSON_NUMBER) - new_msg->thread_trace = (int) jsonObjectGetNumber(tmp); - if(tmp->type == JSON_STRING) - new_msg->thread_trace = atoi(jsonObjectGetString(tmp)); - */ } + /* use the sender's locale, or the global default */ + tmp = jsonObjectGetKey(message, "locale"); + if(tmp) + new_msg->sender_locale = jsonObjectToSimpleString(tmp); + + current_locale = new_msg->sender_locale; tmp = jsonObjectGetKey(message, "protocol"); @@ -266,13 +299,6 @@ int osrf_message_deserialize(char* string, osrf_message* msgs[], int count) { new_msg->protocol = atoi(proto); free(proto); } - - /* - if(tmp->type == JSON_NUMBER) - new_msg->protocol = (int) jsonObjectGetNumber(tmp); - if(tmp->type == JSON_STRING) - new_msg->protocol = atoi(jsonObjectGetString(tmp)); - */ } tmp = jsonObjectGetKey(message, "payload"); diff --git a/src/perlmods/OpenSRF/AppSession.pm b/src/perlmods/OpenSRF/AppSession.pm index 9b2017a..3b79359 100644 --- a/src/perlmods/OpenSRF/AppSession.pm +++ b/src/perlmods/OpenSRF/AppSession.pm @@ -156,6 +156,14 @@ sub last_sent_payload { return $self->{'last_sent_payload'}; } +sub session_locale { + my( $self, $type ) = @_; + if( $type ) { + return $self->{'session_locale'} = $type; + } + return $self->{'session_locale'}; +} + sub last_sent_type { my( $self, $type ) = @_; if( $type ) { @@ -192,9 +200,6 @@ sub stateless { } # When we're a client and we want to connect to a remote service -# create( $app, username => $user, secret => $passwd ); -# OR -# create( $app, sysname => $user, secret => $shared_secret ); sub create { my $class = shift; $class = ref($class) || $class; @@ -202,6 +207,7 @@ sub create { my $app = shift; my $api_level = shift; my $quiet = shift; + my $locale = shift; $api_level = 1 if (!defined($api_level)); @@ -237,6 +243,7 @@ sub create { session_id => $sess_id, remote_id => $r_id, raise_error => $quiet ? 0 : 1, + session_locale => $locale, api_level => $api_level, orig_remote_id => $r_id, peer_handle => $peer_handle, @@ -494,6 +501,7 @@ sub send { $msg->api_level($self->api_level); $msg->payload($payload) if $payload; + $msg->sender_locale($self->session_locale) if $self->session_locale; push @doc, $msg; @@ -742,7 +750,13 @@ sub recv { $logger->debug( "Number of matched responses: " . @list, DEBUG ); $self->queue_wait(0); # check for statuses - return $list[0] unless (wantarray); + if (!wantarray) { + $self->session_locale( $list[0]->sender_locale ); + return $list[0]; + } else { + $self->session_locale( $list[-1]->sender_locale ); + } + return @list; } diff --git a/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm b/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm index 1374e28..495e33a 100644 --- a/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm +++ b/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm @@ -86,6 +86,24 @@ sub api_level { return $self->{api_level}; } +=head2 OpenSRF::DomainObject::oilsMessage->sender_locale( [$locale] ); + +=over 4 + +Sets or gets the current message locale hint. Useful for telling the +server how you see the world. + +=back + +=cut + +sub sender_locale { + my $self = shift; + my $val = shift; + $self->{sender_locale} = $val if (defined $val); + return $self->{sender_locale}; +} + =head2 OpenSRF::DomainObject::oilsMessage->threadTrace( [$new_threadTrace] ); =over 4 -- 2.43.2