/** Linked list of responses to the request. */
osrfMessage* result;
+ /** Buffer used to collect partial response messages */
+ growing_buffer* part_response_buffer;
+
/** Boolean; if true, then a call that is waiting on a response will reset the
timeout and set this variable back to false. */
int reset_timeout;
req->reset_timeout = 0;
req->next = NULL;
req->prev = NULL;
+ req->part_response_buffer = NULL;
return req;
}
req->result = next_msg;
}
+ if (req->part_response_buffer)
+ buffer_free(req->part_response_buffer);
+
free( req );
}
}
if(req == NULL || result == NULL)
return;
+ if (result->status_code == OSRF_STATUS_PARTIAL) {
+ osrfLogDebug(OSRF_LOG_MARK, "received partial message response");
+
+ if (!req->part_response_buffer) {
+ // assume the max_chunk_size of the server matches ours for
+ // buffer initialization, since the setting will usually be
+ // a site-wide value.
+ req->part_response_buffer = buffer_init(OSRF_MSG_CHUNK_SIZE + 1);
+ }
+
+ const char* partial = jsonObjectGetString(result->_result_content);
+
+ if (partial != NULL) {
+ osrfLogDebug(OSRF_LOG_MARK,
+ "adding %d bytes to response buffer", strlen(partial));
+
+ // add the partial contents of the message to the buffer
+ buffer_add(req->part_response_buffer, partial);
+ }
+
+ // all done. req and result are freed by the caller
+ return;
+
+ } else if (result->status_code == OSRF_STATUS_NOCONTENT) {
+ if (req->part_response_buffer && req->part_response_buffer->n_used) {
+
+ // part_response_buffer contains a stitched-together JSON string
+ osrfLogDebug(OSRF_LOG_MARK,
+ "partial response complete, parsing %d bytes",
+ req->part_response_buffer->n_used);
+
+ // coerce the partial-complete response into a standard RESULT.
+ osrf_message_set_status_info(result, NULL, "OK", OSRF_STATUS_OK);
+
+ // use the stitched-together JSON string as the result conten
+ osrf_message_set_result_content(
+ result, req->part_response_buffer->buf);
+
+ // free string, keep the buffer
+ buffer_reset(req->part_response_buffer);
+
+ } else {
+ osrfLogDebug(OSRF_LOG_MARK,
+ "Received OSRF_STATUS_NOCONTENT with no preceeding content");
+ return;
+ }
+ }
+
osrfLogDebug( OSRF_LOG_MARK, "App Session pushing request [%d] onto request queue",
result->thread_trace );
+
if(req->result == NULL) {
req->result = result; // Add the first node
}
/**
+ @brief Split a given string into one or more transport result messages and send it
+ @param session Pointer to the osrfAppSession responsible for sending the message(s).
+ @param request_id Request ID of the osrfAppRequest.
+ @param payload A string to be sent via Jabber.
+ @param payload_size length of payload
+ @param chunk_size chunk_size to use
+
+ @return 0 upon success, or -1 upon failure.
+*/
+int osrfSendChunkedResult(
+ osrfAppSession* session, int request_id, const char* payload,
+ size_t payload_size, size_t chunk_size ) {
+
+ // chunking payload
+ int i;
+ for (i = 0; i < payload_size; i += chunk_size) {
+ osrfMessage* msg = osrf_message_init(RESULT, request_id, 1);
+ osrf_message_set_status_info(msg,
+ "osrfResultPartial",
+ "Partial Response",
+ OSRF_STATUS_PARTIAL
+ );
+
+ // see how long this chunk is. If this is the last
+ // chunk, it will likely be less than chunk_size
+ int partial_size = strlen(&payload[i]);
+ if (partial_size > chunk_size)
+ partial_size = chunk_size;
+
+ // substr(data, i, partial_size)
+ char partial_buf[partial_size + 1];
+ memcpy(partial_buf, &payload[i], partial_size);
+ partial_buf[partial_size] = '\0';
+
+ // package the partial chunk as a JSON string object
+ jsonObject* partial_obj = jsonNewObject(partial_buf);
+ osrf_message_set_result(msg, partial_obj);
+ jsonObjectFree(partial_obj);
+
+ // package the osrf message within an array then
+ // serialize to json for delivery
+ jsonObject* arr = jsonNewObject(NULL);
+
+ // msg json freed when arr is freed
+ jsonObjectPush(arr, osrfMessageToJSON(msg));
+ char* json = jsonObjectToJSON(arr);
+
+ osrfSendTransportPayload(session, json);
+ osrfMessageFree(msg);
+ jsonObjectFree(arr);
+ free(json);
+ }
+
+ // all chunks sent; send the final partial-complete msg
+ osrfMessage* msg = osrf_message_init(RESULT, request_id, 1);
+ osrf_message_set_status_info(msg,
+ "osrfResultPartialComplete",
+ "Partial Response Finalized",
+ OSRF_STATUS_NOCONTENT
+ );
+
+ jsonObject* arr = jsonNewObject(NULL);
+ jsonObjectPush(arr, osrfMessageToJSON(msg));
+ char* json = jsonObjectToJSON(arr);
+ osrfSendTransportPayload(session, json);
+ osrfMessageFree(msg);
+ jsonObjectFree(arr);
+ free(json);
+
+ return 0;
+}
+
+/**
@brief Wrap a given string in a transport message and send it.
@param session Pointer to the osrfAppSession responsible for sending the message(s).
@param payload A string to be sent via Jabber.
OSRF_STATUS_COMPLETE );
if (data) {
- osrfMessage* payload = osrf_message_init( RESULT, requestId, 1 );
- osrf_message_set_status_info( payload, NULL, "OK", OSRF_STATUS_OK );
+ char* json = jsonObjectToJSON(data);
+ size_t raw_size = strlen(json);
+ size_t extra_size = osrfXmlEscapingLength(json);
+ size_t data_size = raw_size + extra_size;
+ size_t chunk_size = OSRF_MSG_CHUNK_SIZE;
- char* json = jsonObjectToJSON( data );
- osrf_message_set_result_content( payload, json );
- free(json);
+ if (data_size > chunk_size) // calculate an escape-scaled chunk size
+ chunk_size = ((double)raw_size / (double)data_size) * (double)chunk_size;
+
+ if (chunk_size > 0 && chunk_size < raw_size) {
+ // chunking -- response message exceeds max message size.
+ // break it up into chunks for partial delivery
+
+ osrfSendChunkedResult(ses, requestId, json, raw_size, chunk_size);
+ osrfAppSessionSendBatch( ses, &status, 1 );
+
+ } else {
+ // message doesn't need to be chunked
+ osrfMessage* payload = osrf_message_init( RESULT, requestId, 1 );
+ osrf_message_set_status_info( payload, NULL, "OK", OSRF_STATUS_OK );
- osrfMessage* ms[2];
- ms[0] = payload;
- ms[1] = status;
+ osrf_message_set_result_content( payload, json );
- osrfAppSessionSendBatch( ses, ms, 2 );
+ osrfMessage* ms[2];
+ ms[0] = payload;
+ ms[1] = status;
+
+ osrfAppSessionSendBatch( ses, ms, 2 );
+
+ osrfMessageFree( payload );
+ }
+
+ free(json);
- osrfMessageFree( payload );
} else {
osrfAppSessionSendBatch( ses, &status, 1 );
}