Exemple #1
0
/**
	@brief Turn a single osrfMessage into a JSON string.
	@param msg Pointer to the osrfMessage to be serialized.
	@return Pointer to the resulting JSON string.

	Translate the osrfMessage into JSON, wrapped in a JSON array.

	This function is equivalent to osrfMessageSerializeBatch() for an array of one pointer.

	The calling code is responsible for freeing the returned string.
*/
char* osrf_message_serialize(const osrfMessage* msg) {

	if( msg == NULL ) return NULL;
	char* j = NULL;

	jsonObject* json = osrfMessageToJSON( msg );

	if(json) {
		jsonObject* wrapper = jsonNewObjectType(JSON_ARRAY);
		jsonObjectPush(wrapper, json);
		j = jsonObjectToJSON(wrapper);
		jsonObjectFree(wrapper);
	}

	return j;
}
Exemple #2
0
/**
	@brief Turn a collection of osrfMessages into one big JSON string.
	@param msgs Pointer to an array of osrfMessages.
	@param count Maximum number of messages to serialize.
	@return Pointer to the JSON string.

	Traverse the array, adding each osrfMessage in turn to a JSON_ARRAY.  Stop when you have added
	the maximum number of messages, or when you encounter a NULL pointer in the array.  Then
	translate the JSON_ARRAY into a JSON string.

	The calling code is responsible for freeing the returned string.
*/
char* osrfMessageSerializeBatch( osrfMessage* msgs [], int count ) {
	if( !msgs ) return NULL;

	jsonObject* wrapper = jsonNewObjectType(JSON_ARRAY);

	int i = 0;
	while( (i < count) && msgs[i] ) {
		jsonObjectPush(wrapper, osrfMessageToJSON( msgs[i] ));
		++i;
	}

	char* j = jsonObjectToJSON(wrapper);
	jsonObjectFree(wrapper);

	return j;
}
static void speedTest() {

    /* creates a giant json object, generating JSON strings
     * of subobjects as it goes. */

    int i,k;
    int count = 50;
    char buf[16];
    char* jsonString;

    jsonObject* array;
    jsonObject* dupe;
    jsonObject* hash = jsonNewObject(NULL);

    for(i = 0; i < count; i++) {
        
        snprintf(buf, sizeof(buf), "key_%d", i);

        array = jsonNewObject(NULL);
        for(k = 0; k < count + i; k++) {
            jsonObjectPush(array, jsonNewNumberObject(k));
            jsonObjectPush(array, jsonNewObject(NULL));
            jsonObjectPush(array, jsonNewObjectFmt("str %d-%d", i, k));
        }
        jsonObjectSetKey(hash, buf, array);

        jsonString = jsonObjectToJSON(hash);
        printf("%s\n\n", jsonString);
        dupe = jsonParse(jsonString);

        jsonObjectFree(dupe);
        free(jsonString);
    }

    jsonObjectFree(hash);
}
/**
 * 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;
}
Exemple #5
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;
}
/**
	@brief Perform a series of sanity tests on an osrfMethodContext.
	@param ctx Pointer to the osrfMethodContext to be checked.
	@return Zero if the osrfMethodContext passes all tests, or -1 if it doesn't.
*/
int osrfMethodVerifyContext( osrfMethodContext* ctx )
{
	if( !ctx ) {
		osrfLogError( OSRF_LOG_MARK,  "Context is NULL in app request" );
		return -1;
	}

	if( !ctx->session ) {
		osrfLogError( OSRF_LOG_MARK, "Session is NULL in app request" );
		return -1;
	}

	if( !ctx->method )
	{
		osrfLogError( OSRF_LOG_MARK, "Method is NULL in app request" );
		return -1;
	}

	if( ctx->method->argc ) {
		if( !ctx->params ) {
			osrfLogError( OSRF_LOG_MARK,
				"Params is NULL in app request %s", ctx->method->name );
			return -1;
		}
		if( ctx->params->type != JSON_ARRAY ) {
			osrfLogError( OSRF_LOG_MARK,
				"'params' is not a JSON array for method %s", ctx->method->name );
			return -1;
		}
	}

	if( !ctx->method->name ) {
		osrfLogError( OSRF_LOG_MARK, "Method name is NULL" );
		 return -1;
	}

	// Log the call, with the method and parameters
	char* params_str = jsonObjectToJSON( ctx->params );
	if( params_str ) {
		// params_str will at minimum be "[]"
		int i = 0;
		const char* str;
		char* method = ctx->method->name;
		int redact_params = 0;
		while( (str = osrfStringArrayGetString(log_protect_arr, i++)) ) {
			//osrfLogInternal(OSRF_LOG_MARK, "Checking for log protection [%s]", str);
			if(!strncmp(method, str, strlen(str))) {
				redact_params = 1;
				break;
			}
		}

		char* params_logged;
		if(redact_params) {
			params_logged = strdup("**PARAMS REDACTED**");
		} else {
			params_str[strlen(params_str) - 1] = '\0'; // drop the trailing ']'
			params_logged = strdup(params_str + 1);
		}
		free( params_str );
		osrfLogInfo( OSRF_LOG_MARK, "CALL: %s %s %s",
			ctx->session->remote_service, ctx->method->name, params_logged);
		free( params_logged );
	}
	return 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;
}