예제 #1
0
파일: oils_auth.c 프로젝트: IISH/Evergreen
/**
 * Fetches the user object from the database and updates the user object in 
 * the cache object, which then has to be re-inserted into the cache.
 * User object is retrieved inside a transaction to avoid replication issues.
 */
static int _oilsAuthReloadUser(jsonObject* cacheObj) {
    int reqid, userId;
    osrfAppSession* session;
	osrfMessage* omsg;
    jsonObject *param, *userObj, *newUserObj = NULL;

    userObj = jsonObjectGetKey( cacheObj, "userobj" );
    userId = oilsFMGetObjectId( userObj );

    session = osrfAppSessionClientInit( "open-ils.cstore" );
    osrfAppSessionConnect(session);

    reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.begin", 1);
	omsg = osrfAppSessionRequestRecv(session, reqid, 60);

    if(omsg) {

        osrfMessageFree(omsg);
        param = jsonNewNumberObject(userId);
        reqid = osrfAppSessionSendRequest(session, param, "open-ils.cstore.direct.actor.user.retrieve", 1);
	    omsg = osrfAppSessionRequestRecv(session, reqid, 60);
        jsonObjectFree(param);

        if(omsg) {
            newUserObj = jsonObjectClone( osrfMessageGetResult(omsg) );
            osrfMessageFree(omsg);
            reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.rollback", 1);
	        omsg = osrfAppSessionRequestRecv(session, reqid, 60);
            osrfMessageFree(omsg);
        }
    }

    osrfAppSessionFree(session); // calls disconnect internally

    if(newUserObj) {

        // ws_ou and wsid are ephemeral and need to be manually propagated
        // oilsFMSetString dupe()'s internally, no need to clone the string
        oilsFMSetString(newUserObj, "wsid", oilsFMGetStringConst(userObj, "wsid"));
        oilsFMSetString(newUserObj, "ws_ou", oilsFMGetStringConst(userObj, "ws_ou"));

        jsonObjectRemoveKey(cacheObj, "userobj"); // this also frees the old user object
        jsonObjectSetKey(cacheObj, "userobj", newUserObj);
        return 1;
    } 

    osrfLogError(OSRF_LOG_MARK, "Error retrieving user %d from database", userId);
    return 0;
}
예제 #2
0
int osrfMathRun( osrfMethodContext* ctx ) {
	if( osrfMethodVerifyContext( ctx ) ) {
		osrfLogError( OSRF_LOG_MARK,  "Invalid method context" );
		return -1;
	}

	/* collect the request params */
	const jsonObject* x = jsonObjectGetIndex(ctx->params, 0);
	const jsonObject* y = jsonObjectGetIndex(ctx->params, 1);

	if( x && y ) {

		/* pull out the params as strings since they may be either
			strings or numbers depending on the client */
		char* a = jsonObjectToSimpleString(x);
		char* b = jsonObjectToSimpleString(y);

		if( a && b ) {

			osrfLogActivity( OSRF_LOG_MARK, "Running opensrf.math %s [ %s : %s ]",
					ctx->method->name, a, b );

			/* construct a new params object to send to dbmath */
			jsonObject* newParams = jsonParseFmt( "[ %s, %s ]", a, b );
			free(a); free(b);

			/* connect to db math */
			osrfAppSession* ses = osrfAppSessionClientInit("opensrf.dbmath");

			/* forcing an explicit connect allows us to talk to one worker backend
			 * regardless of "stateful" config settings for the server
			 * This buys us nothing here since we're only sending one request...
			 * */
			/*osrfAppSessionConnect(ses);*/

			/* dbmath uses the same method names that math does */
			int req_id = osrfAppSessionSendRequest( ses, newParams, ctx->method->name, 1 );
			osrfMessage* omsg = osrfAppSessionRequestRecv( ses, req_id, 60 );
			jsonObjectFree(newParams);

			if(omsg) {
				/* return dbmath's response to the user */
				osrfAppRespondComplete( ctx, osrfMessageGetResult(omsg) );
				osrfMessageFree(omsg);
				osrfAppSessionFree(ses);
				return 0;
			}

			osrfAppSessionFree(ses);
		}
		else {
			if(a)
				free(a);
			if(b)
				free(b);
		}
	}

	return -1;
}
예제 #3
0
int oilsUtilsTrackUserActivity(long usr, const char* ewho, const char* ewhat, const char* ehow) {
    if (!usr && !(ewho || ewhat || ehow)) return 0;
    int rowcount = 0;

    jsonObject* params = jsonParseFmt(
        "{\"from\":[\"actor.insert_usr_activity\", %ld, \"%s\", \"%s\", \"%s\"]}",
        usr, 
        (NULL == ewho)  ? "" : ewho, 
        (NULL == ewhat) ? "" : ewhat, 
        (NULL == ehow)  ? "" : ehow
    );

	osrfAppSession* session = osrfAppSessionClientInit("open-ils.cstore");
    osrfAppSessionConnect(session);
    int reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.begin", 1);
	osrfMessage* omsg = osrfAppSessionRequestRecv(session, reqid, 60);

    if(omsg) {
        osrfMessageFree(omsg);
        reqid = osrfAppSessionSendRequest(session, params, "open-ils.cstore.json_query", 1);
	    omsg = osrfAppSessionRequestRecv(session, reqid, 60);

        if(omsg) {
            const jsonObject* rows = osrfMessageGetResult(omsg);
            if (rows) rowcount = rows->size;
            osrfMessageFree(omsg); // frees rows
            if (rowcount) {
                reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.commit", 1);
	            omsg = osrfAppSessionRequestRecv(session, reqid, 60);
                osrfMessageFree(omsg);
            } else {
                reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.rollback", 1);
	            omsg = osrfAppSessionRequestRecv(session, reqid, 60);
                osrfMessageFree(omsg);
            }
        }
    }

    osrfAppSessionFree(session); // calls disconnect internally
    jsonObjectFree(params);
    return rowcount;
}
예제 #4
0
/**
	@brief Acting as a server, process an incoming osrfMessage.
	@param session Pointer to the osrfAppSession to which the message pertains.
	@param msg Pointer to the osrfMessage.

	Branch on the message type.  In particular, if it's a REQUEST, call the requested method.
*/
static void _do_server( osrfAppSession* session, osrfMessage* msg ) {

	if(session == NULL || msg == NULL) return;

	osrfLogDebug( OSRF_LOG_MARK, "Server received message of type %d", msg->m_type );

        osrf_app_session_set_tz(session, msg->sender_tz);
        osrf_app_session_set_locale(session, msg->sender_locale);

	osrfLogDebug( OSRF_LOG_MARK, "Message has locale %s and tz %s", session->session_locale, session->session_tz );

	switch( msg->m_type ) {

		case STATUS:
			break;

		case DISCONNECT:
			/* session will be freed by the forker */
			osrfLogDebug(OSRF_LOG_MARK, "Client sent explicit disconnect");
			session->state = OSRF_SESSION_DISCONNECTED;
			break;

		case CONNECT:
			osrfAppSessionStatus( session, OSRF_STATUS_OK,
					"osrfConnectStatus", msg->thread_trace, "Connection Successful" );
			session->state = OSRF_SESSION_CONNECTED;
			break;

		case REQUEST:
			osrfLogDebug( OSRF_LOG_MARK, "server passing message %d to application handler "
					"for session %s", msg->thread_trace, session->session_id );

			osrfAppRunMethod( session->remote_service, msg->method_name,
				session, msg->thread_trace, msg->_params );

			break;

		default:
			osrfLogWarning( OSRF_LOG_MARK,
					"Server cannot handle message of type %d", msg->m_type );
			session->state = OSRF_SESSION_DISCONNECTED;
			break;
	}

	osrfMessageFree(msg);
	return;
}
예제 #5
0
/**
	@brief Perform a remote procedure call.
	@param service The name of the service to invoke.
	@param method The name of the method to call.
	@param params The parameters to be passed to the method, if any.
	@return A copy of whatever the method returns as a result, or a JSON_NULL if the method
	doesn't return anything.

	If the @a params parameter points to a JSON_ARRAY, pass each element of the array
	as a separate parameter.  If it points to any other kind of jsonObject, pass it as a
	single parameter.  If it is NULL, pass no parameters.

	The calling code is responsible for freeing the returned object by calling jsonObjectFree().
*/
jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
		const jsonObject* params ) {
	if(!(service && method)) return NULL;

	osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );

	// Open an application session with the service, and send the request
	osrfAppSession* session = osrfAppSessionClientInit( service );
	int reqid = osrfAppSessionSendRequest( session, params, method, 1 );

	// Get the response
	osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
	jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );

	// Clean up
	osrfMessageFree(omsg);
	osrfAppSessionFree(session);
	return result;
}
예제 #6
0
/**
 * Parses the request body, logs any REQUEST messages to the activity log, 
 * stamps the translator ingress on each message, and returns the updated 
 * messages as a JSON string.
 */
static char* osrfHttpTranslatorParseRequest(osrfHttpTranslator* trans) {
    osrfMessage* msg;
    osrfMessage* msgList[MAX_MSGS_PER_PACKET];
    int numMsgs = osrf_message_deserialize(trans->body, msgList, MAX_MSGS_PER_PACKET);
    osrfLogDebug(OSRF_LOG_MARK, "parsed %d opensrf messages in this packet", numMsgs);

    if(numMsgs == 0)
        return NULL;

    // log request messages to the activity log
    int i;
    for(i = 0; i < numMsgs; i++) {
        msg = msgList[i];
        osrfMessageSetIngress(msg, TRANSLATOR_INGRESS);

        switch(msg->m_type) {

            case REQUEST: {
                const jsonObject* params = msg->_params;
                growing_buffer* act = buffer_init(128);	
                char* method = msg->method_name;
                buffer_fadd(act, "[%s] [%s] %s %s", trans->remoteHost, "",
                    trans->service, method);

                const jsonObject* obj = NULL;
                int i = 0;
                const char* str;
                int redactParams = 0;
                while( (str = osrfStringArrayGetString(log_protect_arr, i++)) ) {
                    //osrfLogInternal(OSRF_LOG_MARK, "Checking for log protection [%s]", str);
                    if(!strncmp(method, str, strlen(str))) {
                        redactParams = 1;
                        break;
                    }
                }
                if(redactParams) {
                    OSRF_BUFFER_ADD(act, " **PARAMS REDACTED**");
                } else {
                    i = 0;
                    while((obj = jsonObjectGetIndex(params, i++))) {
                        str = jsonObjectToJSON(obj);
                        if( i == 1 )
                            OSRF_BUFFER_ADD(act, " ");
                        else
                            OSRF_BUFFER_ADD(act, ", ");
                        OSRF_BUFFER_ADD(act, str);
                        free(str);
                    }
                }
                osrfLogActivity(OSRF_LOG_MARK, "%s", act->buf);
                buffer_free(act);
                break;
            }

            case CONNECT:
                trans->connecting = 1;
                if (numMsgs == 1) 
                    trans->connectOnly = 1;
                break;

            case DISCONNECT:
                trans->disconnecting = 1;
                if (numMsgs == 1) 
                    trans->disconnectOnly = 1;
                break;

            case RESULT:
                osrfLogWarning( OSRF_LOG_MARK, "Unexpected RESULT message received" );
                break;

            case STATUS:
                osrfLogWarning( OSRF_LOG_MARK, "Unexpected STATUS message received" );
                break;

            default:
                osrfLogWarning( OSRF_LOG_MARK, "Invalid message type %d received",
                    msg->m_type );
                break;
        }
    }

    char* jsonString = osrfMessageSerializeBatch(msgList, numMsgs);
    for(i = 0; i < numMsgs; i++) {
        osrfMessageFree(msgList[i]);
    }
    return jsonString;
}
예제 #7
0
int osrfVersion( osrfMethodContext* ctx ) {
	if( osrfMethodVerifyContext( ctx ) ) {
		osrfLogError( OSRF_LOG_MARK,  "Invalid method context" );
		return -1;
	}

	/* First, see if the data is in the cache */
	char* json = jsonObjectToJSON(ctx->params);
	char* paramsmd5 = md5sum(json);
	char* cachedmd5 = osrfCacheGetString(paramsmd5);
	free(json);

	if( cachedmd5 ) {
		osrfLogDebug(OSRF_LOG_MARK,  "Found %s object in cache, returning....", cachedmd5 );
		jsonObject* resp = jsonNewObject(cachedmd5);
		osrfAppRespondComplete( ctx, resp  );
		jsonObjectFree(resp);
		free(paramsmd5);
		free(cachedmd5);
		return 0;
	}

	const jsonObject* serv = jsonObjectGetIndex(ctx->params, 0);
	const jsonObject* meth = jsonObjectGetIndex(ctx->params, 1);
	const char* service = jsonObjectGetString(serv);
	const char* methd = jsonObjectGetString(meth);

	if( service && methd ) {
		/* shove the additional params into an array */
		jsonObject* tmpArray = jsonNewObject(NULL);
		int i;
		for( i = 2; i != ctx->params->size; i++ )
			jsonObjectPush( tmpArray, jsonObjectClone(jsonObjectGetIndex(ctx->params, i)));

		osrfAppSession* ses = osrfAppSessionClientInit(service);
		int reqid = osrfAppSessionSendRequest( ses, tmpArray, methd, 1 );
		osrfMessage* omsg = osrfAppSessionRequestRecv( ses, reqid, 60 );
		jsonObjectFree(tmpArray);

		if( omsg ) {

			const jsonObject* result = osrfMessageGetResult( omsg );
			char* resultjson = jsonObjectToJSON(result);
			char* resultmd5 = md5sum(resultjson);
			free(resultjson);
			osrfMessageFree(omsg);

			if( resultmd5 ) {
				jsonObject* resp = jsonNewObject(resultmd5);
				osrfAppRespondComplete( ctx, resp );
				jsonObjectFree(resp);
				osrfAppSessionFree(ses);
				osrfLogDebug(OSRF_LOG_MARK, 
					"Found version string %s, caching and returning...", resultmd5 );
				osrfCachePutString( paramsmd5, resultmd5, OSRF_VERSION_CACHE_TIME );
				free(resultmd5);
				free(paramsmd5);
				return 0;
			}
		}
		osrfAppSessionFree(ses);
	}

	free(paramsmd5);

	return -1;
}
예제 #8
0
//Clean up the test fixture
void teardown(void) {
  osrfMessageFree(o);
}
예제 #9
0
/**
	@brief Acting as a client, process an incoming osrfMessage.
	@param session Pointer to the osrfAppSession to which the message pertains.
	@param msg Pointer to the osrfMessage.

	What we do with the message depends on the combination of message type and status code:
	- If it's a RESULT message, add it to the message queue of the appropriate app session,
	to be handled later.
	- If it's a STATUS message, handle it according to its status code and return NULL --
	unless it has an unexpected status code, in which case add it to the message queue of
	the appropriate app session, to be handled later.
*/
static void _do_client( osrfAppSession* session, osrfMessage* msg ) {
	if(session == NULL || msg == NULL)
		return;

	if( msg->m_type == STATUS ) {

		switch( msg->status_code ) {

			case OSRF_STATUS_OK:
				// This combination of message type and status code comes
				// only from the router, in response to a CONNECT message.
				osrfLogDebug( OSRF_LOG_MARK, "We connected successfully");
				session->state = OSRF_SESSION_CONNECTED;
				osrfLogDebug( OSRF_LOG_MARK,  "State: %x => %s => %d", session,
						session->session_id, session->state );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_COMPLETE:
				osrf_app_session_set_complete( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_CONTINUE:
				osrf_app_session_request_reset_timeout( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_REDIRECTED:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrf_app_session_request_resend( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_EXPFAILED:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_TIMEOUT:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrf_app_session_request_resend( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			default:
			{
				/* Replace the old message with a new one */
				osrfMessage* new_msg = osrf_message_init( 
						RESULT, msg->thread_trace, msg->protocol );
				osrf_message_set_status_info( new_msg,
						msg->status_name, msg->status_text, msg->status_code );
				osrfLogWarning( OSRF_LOG_MARK, "The stack doesn't know what to do with "
						"the provided message code: %d, name %s. Passing UP.",
						msg->status_code, msg->status_name );
				new_msg->is_exception = 1;
				osrf_app_session_set_complete( session, msg->thread_trace );
				osrfLogDebug( OSRF_LOG_MARK, 
						"passing client message %d / session %s to app handler",
						msg->thread_trace, session->session_id );
				osrfMessageFree(msg);
				// Enqueue the new message to be processed later
				osrf_app_session_push_queue( session, new_msg );
				break;
			} // end default
		} // end switch

	} else if( msg->m_type == RESULT ) {
		osrfLogDebug( OSRF_LOG_MARK, "passing client message %d / session %s to app handler",
					  msg->thread_trace, session->session_id );
		// Enqueue the RESULT message to be processed later
		osrf_app_session_push_queue( session, msg );

	}

	return;
}
예제 #10
0
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;


	osrf_json_gateway_dir_config* dir_conf =
		ap_get_module_config(r->per_dir_config, &osrf_json_gateway_module);


	/* provide 2 different JSON parsers and serializers to support legacy JSON */
	jsonObject* (*parseJSONFunc) (const char*) = legacy_jsonParseString;
	char* (*jsonToStringFunc) (const jsonObject*) = legacy_jsonObjectToJSON;

	if(dir_conf->legacyJSON) {
		ap_log_rerror( APLOG_MARK, APLOG_DEBUG, 0, r, "Using legacy JSON");

	} else {
		parseJSONFunc = jsonParse;
		jsonToStringFunc = jsonObjectToJSON;
	}


	osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: entered request handler");

	/* verify we are connected */
	if( !bootstrapped || !osrfSystemGetTransportClient()) {
		ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, r, "Cannot process request "
				"because the OpenSRF JSON gateway has not been bootstrapped...");
		usleep( 100000 ); /* 100 milliseconds */
		exit(1);
	}

	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 */
	char* a_l           = NULL;  /* request api level */
	char* input_format  = NULL;  /* POST data format, defaults to 'format' */
	int   isXML         = 0;
	int   api_level     = 1;

	r->allowed |= (AP_METHOD_BIT << M_GET);
	r->allowed |= (AP_METHOD_BIT << M_POST);

	osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: parsing URL params");
	osrfStringArray* mparams = NULL;
	osrfStringArray* params  = apacheParseParms(r); /* free me */
	param_locale             = apacheGetFirstParamValue( params, "locale" );
	service                  = apacheGetFirstParamValue( params, "service" );
	method                   = apacheGetFirstParamValue( params, "method" );
	format                   = apacheGetFirstParamValue( params, "format" );
	input_format             = apacheGetFirstParamValue( params, "input_format" );
	a_l                      = apacheGetFirstParamValue( params, "api_level" );
	mparams                  = apacheGetParamValues( params, "param" ); /* free me */

	if(format == NULL)
		format = strdup( "json" );
	if(input_format == NULL)
		input_format = strdup( format );

	/* set the user defined timeout value */
	int timeout = 60;
	char* tout = apacheGetFirstParamValue( params, "timeout" ); /* request timeout in seconds */
	if( tout ) {
		timeout = atoi(tout);
		osrfLogDebug(OSRF_LOG_MARK, "Client supplied timeout of %d", timeout);
		free( tout );
	}

	if (a_l) {
		api_level = atoi(a_l);
		free( a_l );
	}

	if (!strcasecmp(format, "xml")) {
		isXML = 1;
		ap_set_content_type(r, "application/xml");
	} else {
		ap_set_content_type(r, "text/plain");
	}

	free( format );
	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 && 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)) {

		osrfLogError(OSRF_LOG_MARK,
			"Service [%s] not found or not allowed", service);
		ret = HTTP_NOT_FOUND;

	} else {

		/* This will log all heaers to the apache error log
		const apr_array_header_t* arr = apr_table_elts(r->headers_in);
		const void* ptr;

		while( (ptr = apr_array_pop(arr)) ) {
			apr_table_entry_t* e = (apr_table_entry_t*) ptr;
			fprintf(stderr, "Table entry: %s : %s\n", e->key, e->val );
		}
		fflush(stderr);
		*/

		osrfAppSession* session = osrfAppSessionClientInit(service);
		osrf_app_session_set_locale(session, osrf_locale);

		double starttime = get_timestamp_millis();
		int req_id = -1;

		if(!strcasecmp(input_format, "json")) {
			jsonObject * arr = jsonNewObject(NULL);

			const char* str;
			int i = 0;

			while( (str = osrfStringArrayGetString(mparams, i++)) )
				jsonObjectPush(arr, parseJSONFunc(str));

			req_id = osrfAppSessionSendRequest( session, arr, method, api_level );
			jsonObjectFree(arr);
		} else {

			/**
			* If we receive XML method params, convert each param to a JSON object
			* and pass the array of JSON object params to the method */
			if(!strcasecmp(input_format, "xml")) {
				jsonObject* jsonParams = jsonNewObject(NULL);

				const char* str;
				int i = 0;
				while( (str = osrfStringArrayGetString(mparams, i++)) ) {
					jsonObjectPush(jsonParams, jsonXMLToJSONObject(str));
				}

				req_id = osrfAppSessionSendRequest( session, jsonParams, method, api_level );
				jsonObjectFree(jsonParams);
			}
		}


		if( req_id == -1 ) {
			osrfLogError(OSRF_LOG_MARK, "I am unable to communicate with opensrf..going away...");
			osrfAppSessionFree(session);
			/* we don't want to spawn an intense re-forking storm
			 * if there is no jabber server.. so give it some time before we die */
			usleep( 100000 ); /* 100 milliseconds */
			exit(1);
		}


		/* ----------------------------------------------------------------- */
		/* log all requests to the activity log */
		const char* authtoken = apr_table_get(r->headers_in, "X-OILS-Authtoken");
		if(!authtoken) authtoken = "";
		growing_buffer* act = buffer_init(128);
		buffer_fadd(act, "[%s] [%s] [%s] %s %s", r->connection->remote_ip,
			authtoken, osrf_locale, service, method );
		const char* str; int i = 0;
		while( (str = osrfStringArrayGetString(mparams, i++)) ) {
			if( i == 1 ) {
				OSRF_BUFFER_ADD(act, " ");
				OSRF_BUFFER_ADD(act, str);
			} else {
				OSRF_BUFFER_ADD(act, ", ");
				OSRF_BUFFER_ADD(act, str);
			}
		}

		osrfLogActivity( OSRF_LOG_MARK, act->buf );
		buffer_free(act);
		/* ----------------------------------------------------------------- */


		osrfMessage* omsg = NULL;

		int statuscode = 200;

		/* kick off the object */
		if (isXML)
			ap_rputs( "<response xmlns=\"http://opensrf.org/-/namespaces/gateway/v1\"><payload>",
				r );
		else
			ap_rputs("{\"payload\":[", r);

		int morethan1       = 0;
		char* statusname    = NULL;
		char* statustext    = NULL;
		char* output        = NULL;

		while((omsg = osrfAppSessionRequestRecv( session, req_id, timeout ))) {

			statuscode = omsg->status_code;
			const jsonObject* res;

			if( ( res = osrfMessageGetResult(omsg)) ) {

				if (isXML) {
					output = jsonObjectToXML( res );
				} else {
					output = jsonToStringFunc( res );
					if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */
				}
				ap_rputs(output, r);
				free(output);
				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 );
				}
			}

			osrfMessageFree(omsg);
			if(statusname) break;
		}

		double duration = get_timestamp_millis() - starttime;
		osrfLogDebug(OSRF_LOG_MARK, "gateway request took %f seconds", duration);


		if (isXML)
			ap_rputs("</payload>", r);
		else
			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) + 32;
			char buf[l];

			if (isXML)
				snprintf( buf, sizeof(buf), "<debug>\"%s : %s\"</debug>", statusname, statustext );

			else {
				char bb[l];
				snprintf(bb, sizeof(bb),  "%s : %s", statusname, statustext);
				jsonObject* tmp = jsonNewObject(bb);
				char* j = jsonToStringFunc(tmp);
				snprintf( buf, sizeof(buf), ",\"debug\": %s", j);
				free(j);
				jsonObjectFree(tmp);
			}

			ap_rputs(buf, r);

			free(statusname);
			free(statustext);
		}

		/* insert the status code */
		char buf[32];

		if (isXML)
			snprintf(buf, sizeof(buf), "<status>%d</status>", statuscode );
		else
			snprintf(buf, sizeof(buf), ",\"status\":%d", statuscode );

		ap_rputs( buf, r );

		if (isXML)
			ap_rputs("</response>", r);
		else
			ap_rputs( "}", r ); /* finish off the object */

		osrfAppSessionFree(session);
	}

	osrfLogInfo(OSRF_LOG_MARK, "Completed processing service=%s, method=%s", service, method);
	osrfStringArrayFree(params);
	osrfStringArrayFree(mparams);
	free( osrf_locale );
	free( input_format );
	free( method );
	free( service );

	osrfLogDebug(OSRF_LOG_MARK, "Gateway served %d requests", ++numserved);
	osrfLogClearXid();

	return ret;
}
예제 #11
0
/**
	@brief Either send or enqueue a response to a client, optionally with a completion notice.
	@param ctx Pointer to the method context.
	@param data Pointer to the response, in the form of a jsonObject.
	@param complete Boolean: if true, we will accompany the RESULT message with a STATUS
	message indicating that the response is complete.
	@return Zero if successful, or -1 upon error.

	For an atomic method, add a copy of the response data to a cache within the method
	context, to be sent later.  In this case the @a complete parameter has no effect,
	because we'll send the STATUS message later when we send the cached results.

	If the method is not atomic, translate the message into JSON and append it to a buffer,
	flushing the buffer as needed to avoid overflow.  If @a complete is true, append
	a STATUS message (as JSON) to the buffer and flush the buffer.
*/
static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int complete ) {
	if(!(ctx && ctx->method)) return -1;

	if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
		osrfLogDebug( OSRF_LOG_MARK,
			"Adding responses to stash for atomic method %s", ctx->method->name );

		// If we don't already have one, create a JSON_ARRAY to serve as a cache.
		if( ctx->responses == NULL )
			ctx->responses = jsonNewObjectType( JSON_ARRAY );

		// Add a copy of the data object to the cache.
		if ( data != NULL )
			jsonObjectPush( ctx->responses, jsonObjectClone(data) );
	} else {
		osrfLogDebug( OSRF_LOG_MARK,
			"Adding responses to stash for method %s", ctx->method->name );

		if( data ) {
			// If you want to flush the intput buffers for every output message,
			// this is the place to do it.
			//osrf_app_session_queue_wait( ctx->session, 0, NULL );

			// Create an OSRF message
			osrfMessage* msg = osrf_message_init( RESULT, ctx->request, 1 );
			osrf_message_set_status_info( msg, NULL, "OK", OSRF_STATUS_OK );
			osrf_message_set_result( msg, data );

			// Serialize the OSRF message into JSON text
			char* json = jsonObjectToJSON( osrfMessageToJSON( msg ));
			osrfMessageFree( msg );

			// If the new message would overflow the buffer, flush the output buffer first
			int len_so_far = buffer_length( ctx->session->outbuf );
			if( len_so_far && (strlen( json ) + len_so_far + 3 >= ctx->method->bufsize )) {
				if( flush_responses( ctx->session, ctx->session->outbuf ))
					return -1;
			}

			// Append the JSON text to the output buffer
			append_msg( ctx->session->outbuf, json );
			free( json );
		}

		if(complete) {
			// Create a STATUS message
			osrfMessage* status_msg = osrf_message_init( STATUS, ctx->request, 1 );
			osrf_message_set_status_info( status_msg, "osrfConnectStatus", "Request Complete",
				OSRF_STATUS_COMPLETE );

			// Serialize the STATUS message into JSON text
			char* json = jsonObjectToJSON( osrfMessageToJSON( status_msg ));
			osrfMessageFree( status_msg );

			// Add the STATUS message to the output buffer.
			// It's short, so don't worry about avoiding overflow.
			append_msg( ctx->session->outbuf, json );
			free( json );

			// Flush the output buffer, sending any accumulated messages.
			if( flush_responses( ctx->session, ctx->session->outbuf ))
				return -1;
		}
	}

	return 0;
}
static char* extract_inbound_messages(
        const request_rec *r, 
        const char* service, 
        const char* thread, 
        const char* recipient, 
        const jsonObject *osrf_msg) {

    int i;
    int num_msgs = osrf_msg->size;
    osrfMessage* msg;
    osrfMessage* msg_list[num_msgs];

    // here we do an extra json round-trip to get the data
    // in a form osrf_message_deserialize can understand
    // TODO: consider a version of osrf_message_init which can 
    // accept a jsonObject* instead of a JSON string.
    char *osrf_msg_json = jsonObjectToJSON(osrf_msg);
    osrf_message_deserialize(osrf_msg_json, msg_list, num_msgs);
    free(osrf_msg_json);

    // should we require the caller to always pass the service?
    if (service == NULL) service = "";

    for(i = 0; i < num_msgs; i++) {
        msg = msg_list[i];
        osrfMessageSetIngress(msg, WEBSOCKET_TRANSLATOR_INGRESS);

        switch(msg->m_type) {

            case REQUEST: {
                const jsonObject* params = msg->_params;
                growing_buffer* act = buffer_init(128);
                char* method = msg->method_name;
                buffer_fadd(act, "[%s] [%s] %s %s", 
                    get_client_ip(r), "", service, method);

                const jsonObject* obj = NULL;
                int i = 0;
                const char* str;
                int redactParams = 0;
                while( (str = osrfStringArrayGetString(log_protect_arr, i++)) ) {
                    if(!strncmp(method, str, strlen(str))) {
                        redactParams = 1;
                        break;
                    }
                }
                if(redactParams) {
                    OSRF_BUFFER_ADD(act, " **PARAMS REDACTED**");
                } else {
                    i = 0;
                    while((obj = jsonObjectGetIndex(params, i++))) {
                        char* str = jsonObjectToJSON(obj);
                        if( i == 1 )
                            OSRF_BUFFER_ADD(act, " ");
                        else
                            OSRF_BUFFER_ADD(act, ", ");
                        OSRF_BUFFER_ADD(act, str);
                        free(str);
                    }
                }
                osrfLogActivity(OSRF_LOG_MARK, "%s", act->buf);
                buffer_free(act);
                requests_in_flight++;
                break;
            }

            case DISCONNECT:
                clear_cached_recipient(thread);
                break;
        }
    }

    char* finalMsg = osrfMessageSerializeBatch(msg_list, num_msgs);

    // clean up our messages
    for(i = 0; i < num_msgs; i++) 
        osrfMessageFree(msg_list[i]);

    return finalMsg;
}