[OpenSRF-GIT] OpenSRF branch master updated. dbf9ec150dfa6a5b87028aa890a80b529dfe5683

Evergreen Git git at git.evergreen-ils.org
Tue Nov 1 17:13:55 EDT 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "OpenSRF".

The branch, master has been updated
       via  dbf9ec150dfa6a5b87028aa890a80b529dfe5683 (commit)
       via  76a5fd0055b2af25f0783825c951021a32a5f17d (commit)
       via  4f73f38bae3892fa4f6b3980c5724af521a31fde (commit)
       via  d79c7eee6ce44bd3b38bd712d487cb31752c3a31 (commit)
       via  fd1ce3521553d6ddbc42762090be8ecdbc0b39f2 (commit)
       via  75a9906d5a5e90c60c8e0614e0c71796c511ec18 (commit)
       via  18be4a4cf242a274cf5a3143c2063d75331ec7c0 (commit)
       via  b3b6b4211472e4897581a93d9615d8544f29779f (commit)
       via  56e65d1e6fb4ee72b28b4e008b9461d5bac55b8d (commit)
       via  01f95834835bed94df93a7fdad59e38486e6485a (commit)
      from  784233808062dbc599b649ce9858759ab0a8dff3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit dbf9ec150dfa6a5b87028aa890a80b529dfe5683
Author: Galen Charlton <gmc at esilibrary.com>
Date:   Tue Nov 1 16:30:26 2016 -0400

    LP#1612771: add release notes
    
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/doc/Bundling-and-Chunking.txt b/doc/Bundling-and-Chunking.txt
new file mode 100644
index 0000000..39843f4
--- /dev/null
+++ b/doc/Bundling-and-Chunking.txt
@@ -0,0 +1,19 @@
+Message Bundling and Chunking
+=============================
+
+OpenSRF now supports message chunking, i.e., breaking up large OpenSRF
+messages across multiple XMPP envelopes. This is implemented with a
+new OpenSRF message type.
+
+C, Perl, and Javascript libraries are taught how to reconstruct chunked
+messages. The default chunking threshold is 50Kb, just a bit below the
+default ejabberd max stanza size of 64Kb.
+
+What was previously called chunking is now referred to as bundling:
+packing multiple OpenSRF messages together in a single XMPP envelope,
+as long as we believe more messages will be sent in the future and we
+are below some threshold of combined message size.  The default for
+that threshold is 25Kb.
+
+With this change, it is no longer necessary to change the `max_stanza_size`
+setting for ejabberd when installing OpenSRF.

commit 76a5fd0055b2af25f0783825c951021a32a5f17d
Author: Galen Charlton <gmc at esilibrary.com>
Date:   Tue Nov 1 16:22:10 2016 -0400

    LP#1612771: fix error in POD
    
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
index 307eb57..874a4ae 100644
--- a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
+++ b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
@@ -340,7 +340,7 @@ $statusCode = STATUS_NOCONTENT;
 
 =head1 NAME
 
-OpenSRF::DomainObject::oilsResult::Partial
+OpenSRF::DomainObject::oilsResult::PartialComplete
 
 =head1 SYNOPSIS
 

commit 4f73f38bae3892fa4f6b3980c5724af521a31fde
Author: Galen Charlton <gmc at esilibrary.com>
Date:   Tue Nov 1 16:03:50 2016 -0400

    LP#1612771: update protocol documentation
    
    Now that we have PARTIAL and NOCONTENT statuses, let's
    mention them in the documentation for the benefit of
    folks writing future clients.
    
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/doc/OpenSRF-Messaging-Protocol.html b/doc/OpenSRF-Messaging-Protocol.html
index 1eeff04..590f136 100644
--- a/doc/OpenSRF-Messaging-Protocol.html
+++ b/doc/OpenSRF-Messaging-Protocol.html
@@ -38,7 +38,9 @@
 		<b> <pre style="border: solid thin blue; margin: 2% 10% 2% 10%; padding-left: 50px">
 		100	STATUS_CONTINUE
 		200	STATUS_OK	
+		204	STATUS_NOCONTENT
 		205	STATUS_COMPLETE
+		206	STATUS_PARTIAL
 		307	STATUS_REDIRECTED
 		400	STATUS_BADREQUEST
 		404	STATUS_NOTFOUND
@@ -137,7 +139,13 @@ while ( more requests ) {
 				the request is now complete, nothing more to be done with this request
 				break out of loop
 	
-		if ( response.typ == RESULT )
+		if ( response.type == RESULT )
+
+			if    ( response.statusCode == STATUS_PARTIAL )
+				add response chunk to buffer
+				continue receiving response chunks
+			elsif ( response.statusCode == STATUS_NOCONTENT )
+				have whole response, use buffer as result
 
 			pass result to the application layer for processing
 

commit d79c7eee6ce44bd3b38bd712d487cb31752c3a31
Author: Galen Charlton <gmc at esilibrary.com>
Date:   Tue Nov 1 15:46:13 2016 -0400

    LP#1612771: don't adjust max_stanza_size during installation
    
    As the typical max_stanza_size for ejabberd installations
    is larger than what OpenSRF now needs, this patch adjusts
    the installation instructions to remove the step to change
    max_stanza_size.
    
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/README b/README
index bb1228d..a5b3324 100644
--- a/README
+++ b/README
@@ -203,10 +203,9 @@ changes:
 {hosts, ["localhost", "private.localhost", "public.localhost"]}.
 ---------------------------------------------------------------------------
 +
-  b. Change all `max_stanza_size` values to 2000000
-  c. Change all `maxrate` values to 500000
-  d. Increase the `max_user_sessions` value to 10000
-  e. Comment out the `mod_offline` directive
+  b. Change all `maxrate` values to 500000
+  c. Increase the `max_user_sessions` value to 10000
+  d. Comment out the `mod_offline` directive
 +
 (Debian Jessie) Ejabberd 13.x and 14.x::
 Open `/etc/ejabberd/ejabberd.yml` and make the following
@@ -222,10 +221,9 @@ hosts:
   - "public.localhost"
 ---------------------------------------------------------------------------
 +
-  b. Change all `max_stanza_size` values to 2000000
-  c. Change `shaper:` `normal` and `fast` values to 500000
-  d. Increase the `max_user_sessions:` `all:` value to 10000
-  e. Comment out the `mod_offline` directive
+  b. Change `shaper:` `normal` and `fast` values to 500000
+  c. Increase the `max_user_sessions:` `all:` value to 10000
+  d. Comment out the `mod_offline` directive
 +
 -----------------------
 ##mod_offline:
@@ -246,11 +244,10 @@ hosts:
   - "public.localhost"
 ---------------------------------------------------------------------------
 +
-  b. Change all `max_stanza_size` values to 2000000
-  c. Change `auth_password_format` to plain
-  d. Change `shaper:` `normal` and `fast` values to 500000
-  e. Increase the `max_user_sessions:` `all:` value to 10000
-  f. Comment out the `mod_offline` directive
+  b. Change `auth_password_format` to plain
+  c. Change `shaper:` `normal` and `fast` values to 500000
+  d. Increase the `max_user_sessions:` `all:` value to 10000
+  e. Comment out the `mod_offline` directive
 +
 -----------------------
 ##mod_offline:

commit fd1ce3521553d6ddbc42762090be8ecdbc0b39f2
Author: Mike Rylander <mrylander at gmail.com>
Date:   Sun Feb 23 15:55:52 2014 -0500

    LP#1612771: Add chunking support to JS implementation
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/include/opensrf/osrf_message.h b/include/opensrf/osrf_message.h
index 14b601b..1785adf 100644
--- a/include/opensrf/osrf_message.h
+++ b/include/opensrf/osrf_message.h
@@ -38,6 +38,9 @@ extern "C" {
 #define OSRF_STATUS_ACCEPTED             202
 #define OSRF_STATUS_COMPLETE             205
 
+#define OSRF_STATUS_PARTIAL              206
+#define OSRF_STATUS_NOCONTENT            204
+
 #define OSRF_STATUS_REDIRECTED           307
 
 #define OSRF_STATUS_BADREQUEST           400
diff --git a/src/javascript/opensrf.js b/src/javascript/opensrf.js
index 414233f..394cddd 100644
--- a/src/javascript/opensrf.js
+++ b/src/javascript/opensrf.js
@@ -45,7 +45,9 @@ var OSRF_MESSAGE_TYPE_DISCONNECT = 'DISCONNECT';
 var OSRF_STATUS_CONTINUE = 100;
 var OSRF_STATUS_OK = 200;
 var OSRF_STATUS_ACCEPTED = 202;
+var OSRF_STATUS_NOCONTENT = 204;
 var OSRF_STATUS_COMPLETE = 205;
+var OSRF_STATUS_PARTIAL = 206;
 var OSRF_STATUS_REDIRECTED = 307;
 var OSRF_STATUS_BADREQUEST = 400;
 var OSRF_STATUS_UNAUTHORIZED = 401;
@@ -186,6 +188,45 @@ osrfResult.prototype.content = function(d) {
         this.hash.content = d; 
     return this.hash.content; 
 };
+function osrfResultPartial(hash) {
+    this.hash = hash;
+    this._encodehash = true;
+}
+osrfResultPartial.prototype.status = function(d) {
+    if(arguments.length == 1) 
+        this.hash.status = d; 
+    return this.hash.status; 
+};
+osrfResultPartial.prototype.statusCode = function(d) {
+    if(arguments.length == 1) 
+        this.hash.statusCode = d; 
+    return this.hash.statusCode; 
+};
+osrfResultPartial.prototype.content = function(d) {
+    if(arguments.length == 1) 
+        this.hash.content = d; 
+    return this.hash.content; 
+};
+function osrfResultPartialComplete(hash) {
+    this.hash = hash;
+    this._encodehash = true;
+}
+osrfResultPartialComplete.prototype.status = function(d) {
+    if(arguments.length == 1) 
+        this.hash.status = d; 
+    return this.hash.status; 
+};
+osrfResultPartialComplete.prototype.statusCode = function(d) {
+    if(arguments.length == 1) 
+        this.hash.statusCode = d; 
+    return this.hash.statusCode; 
+};
+osrfResultPartialComplete.prototype.content = function(d) {
+    if(arguments.length == 1) 
+        this.hash.content = d; 
+    return this.hash.content; 
+};
+
 function osrfServerError(hash) { 
     this.hash = hash;
     this._encodehash = true;
@@ -508,6 +549,7 @@ OpenSRF.Request = function(session, reqid, args) {
     this.timeout = args.timeout;
     this.api_level = args.api_level || OpenSRF.api_level;
     this.response_queue = [];
+    this.part_response_buffer = '';
     this.complete = false;
 };
 
@@ -632,11 +674,12 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg) {
     
     var req = ses.find_request(osrf_msg.threadTrace());
 
+    var payload = osrf_msg.payload();
+    var status = payload.statusCode();
+    var status_text = payload.status();
+
     if(osrf_msg.type() == OSRF_MESSAGE_TYPE_STATUS) {
 
-        var payload = osrf_msg.payload();
-        var status = payload.statusCode();
-        var status_text = payload.status();
 
         if(status == OSRF_STATUS_COMPLETE) {
             if(req) {
@@ -666,11 +709,19 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg) {
     }
 
     if(osrf_msg.type() == OSRF_MESSAGE_TYPE_RESULT) {
+        req = ses.find_request(osrf_msg.threadTrace());
         if(req) {
-            req.response_queue.push(osrf_msg.payload());
-            if(req.onresponse) {
-                return req.onresponse(req);
+            if (status == OSRF_STATUS_PARTIAL) {
+                req.part_response_buffer += payload.content()
+                return; // we're just collecting a big chunked payload
+            } else if (status == OSRF_STATUS_NOCONTENT) {
+                payload.content( JSON2js(req.part_response_buffer) );
+                payload.statusCode( OSRF_STATUS_OK );
+                req.part_response_buffer = '';
             }
+            req.response_queue.push(payload);
+            if(req.onresponse) 
+                return req.onresponse(req);
         }
     }
 };

commit 75a9906d5a5e90c60c8e0614e0c71796c511ec18
Author: Bill Erickson <berick at esilibrary.com>
Date:   Fri Feb 28 12:44:11 2014 -0500

    LP#1612771: implement C max_chunk_size server support
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/src/libopensrf/osrf_application.c b/src/libopensrf/osrf_application.c
index b79a778..cbd9371 100644
--- a/src/libopensrf/osrf_application.c
+++ b/src/libopensrf/osrf_application.c
@@ -733,29 +733,100 @@ static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int
 			"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->max_bundle_size )) {
-				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 );
+            char* data_str = jsonObjectToJSON(data); // free me (below)
+            size_t data_size = strlen(data_str);
+            size_t chunk_size = ctx->method->max_chunk_size;
+
+            if (chunk_size > 0 && chunk_size < data_size) {
+                // chunking -- response message exceeds max message size.
+                // break it up into chunks for partial delivery
+                
+                int i;
+                for (i = 0; i < data_size; i += chunk_size) {
+
+                    osrfMessage* msg = 
+                        osrf_message_init(RESULT, ctx->request, 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(&data_str[i]);
+                    if (partial_size > chunk_size) 
+                        partial_size = chunk_size;
+
+                    // substr(data_str, i, partial_size)
+                    char partial_buf[partial_size + 1];
+                    memcpy(partial_buf, &data_str[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(ctx->session, json);
+                    osrfMessageFree(msg);
+                    jsonObjectFree(arr);
+                    free(json);
+                }
+
+                // all chunks sent; send the final partial-complete msg
+                osrfMessage* msg = 
+                    osrf_message_init(RESULT, ctx->request, 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(ctx->session, json);
+                osrfMessageFree(msg);
+                jsonObjectFree(arr);
+                free(json);
+
+
+            } else {
+
+                // bundling -- message body (may be) too small for single
+                // delivery.  prepare message for bundling.
+
+                // 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->max_bundle_size )) {
+                    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 );
+            }
+
+            free(data_str);
 		}
 
 		if(complete) {
diff --git a/src/libopensrf/osrf_message.c b/src/libopensrf/osrf_message.c
index 9de5e0f..e7aae08 100644
--- a/src/libopensrf/osrf_message.c
+++ b/src/libopensrf/osrf_message.c
@@ -489,7 +489,13 @@ jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
 		case RESULT:
 			jsonObjectSetKey(json, "type", jsonNewObject("RESULT"));
 			payload = jsonNewObject(NULL);
-			jsonObjectSetClass(payload,"osrfResult");
+            char* cname = "osrfResult";
+            if (msg->status_code == OSRF_STATUS_PARTIAL) {
+                cname = "osrfResultPartial";
+            } else if (msg->status_code == OSRF_STATUS_NOCONTENT) {
+                cname = "osrfResultPartialComplete";
+            }
+			jsonObjectSetClass(payload, cname);
 			jsonObjectSetKey(payload, "status", jsonNewObject(msg->status_text));
 			snprintf(sc, sizeof(sc), "%d", msg->status_code);
 			jsonObjectSetKey(payload, "statusCode", jsonNewObject(sc));

commit 18be4a4cf242a274cf5a3143c2063d75331ec7c0
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Feb 27 15:18:15 2014 -0500

    LP#1612771: set Perl / C max_chunk_size default sizes
    
    default max bundle size == 25K
    default max chunk size  == 50K
    
    Note with Ejabberd using 65536 as the default max stanza size, these
    new OpenSRF defaults mean that all messages will fit the default
    message size constraints -- i.e. no more need to raise the
    max_stanza_size.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/include/opensrf/osrf_app_session.h b/include/opensrf/osrf_app_session.h
index 9c9efad..d635323 100644
--- a/include/opensrf/osrf_app_session.h
+++ b/include/opensrf/osrf_app_session.h
@@ -34,7 +34,12 @@ struct osrf_app_request_struct;
 typedef struct osrf_app_request_struct osrfAppRequest;
 
 #define OSRF_REQUEST_HASH_SIZE 64
-#define OSRF_MSG_CHUNK_SIZE    104858 /* 0.1 MB */
+
+/**
+	@brief Default size of output buffer.
+*/
+#define OSRF_MSG_BUNDLE_SIZE 25600 /* 25K */
+#define OSRF_MSG_CHUNK_SIZE  (OSRF_MSG_BUNDLE_SIZE * 2)
 
 /**
 	@brief Representation of a session with another application.
diff --git a/src/libopensrf/osrf_application.c b/src/libopensrf/osrf_application.c
index 03eb7a3..b79a778 100644
--- a/src/libopensrf/osrf_application.c
+++ b/src/libopensrf/osrf_application.c
@@ -87,11 +87,6 @@
 /*@}*/
 
 /**
-	@brief Default size of output buffer.
-*/
-#define OSRF_MSG_BUNDLE_SIZE     10240
-
-/**
 	@brief Represent an Application.
 */
 typedef struct {
diff --git a/src/perl/lib/OpenSRF/Application.pm b/src/perl/lib/OpenSRF/Application.pm
index 8aec164..9a958e0 100644
--- a/src/perl/lib/OpenSRF/Application.pm
+++ b/src/perl/lib/OpenSRF/Application.pm
@@ -52,7 +52,7 @@ sub max_bundle_size {
 	my $self = shift;
 	return 0 unless ref($self);
 	return $self->{max_bundle_size} if (defined($self->{max_bundle_size}));
-	return 10240;
+	return 25600; # 25K
 }
 
 sub max_bundle_count {
@@ -65,7 +65,7 @@ sub max_chunk_size {
 	my $self = shift;
 	return 0 unless ref($self);
 	return $self->{max_chunk_size} if (defined($self->{max_chunk_size}));
-	return 104858; # 1/10 MB
+	return $self->max_bundle_size * 2;
 }
 
 sub api_name {

commit b3b6b4211472e4897581a93d9615d8544f29779f
Author: Mike Rylander <mrylander at gmail.com>
Date:   Sun Feb 23 16:35:17 2014 -0500

    LP#1612771: C support for receiving chunked responses
    
    * client parsing
    * consistent w/ Perl, we now have "bundling" and "chunking"
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/include/opensrf/osrf_app_session.h b/include/opensrf/osrf_app_session.h
index 57d9092..9c9efad 100644
--- a/include/opensrf/osrf_app_session.h
+++ b/include/opensrf/osrf_app_session.h
@@ -34,6 +34,7 @@ struct osrf_app_request_struct;
 typedef struct osrf_app_request_struct osrfAppRequest;
 
 #define OSRF_REQUEST_HASH_SIZE 64
+#define OSRF_MSG_CHUNK_SIZE    104858 /* 0.1 MB */
 
 /**
 	@brief Representation of a session with another application.
diff --git a/include/opensrf/osrf_application.h b/include/opensrf/osrf_application.h
index e50e114..68b096c 100644
--- a/include/opensrf/osrf_application.h
+++ b/include/opensrf/osrf_application.h
@@ -91,7 +91,8 @@ typedef struct {
 	//char* paramNotes;         /**< Description of the params expected for this method. */
 	int options;                /**< Bit switches setting various options for this method. */
 	void* userData;             /**< Opaque pointer to application-specific data. */
-	size_t bufsize;             /**< How big a buffer to use for non-atomic methods */
+	size_t max_bundle_size;     /**< How big a buffer to use for non-atomic methods */
+	size_t max_chunk_size;      /**< Maximum content size per message; 0 means no limit */
 
 	/*
 	int sysmethod;
@@ -117,7 +118,7 @@ int osrfAppRegisterMethod( const char* appName, const char* methodName,
 int osrfAppRegisterExtendedMethod( const char* appName, const char* methodName,
 		const char* symbolName, const char* notes, int argc, int options, void* );
 
-int osrfMethodSetBufferSize( const char* appName, const char* methodName, size_t bufsize );
+int osrfMethodSetBundleSize( const char* appName, const char* methodName, size_t max_bundle_size );
 
 osrfMethod* _osrfAppFindMethod( const char* appName, const char* methodName );
 
diff --git a/src/libopensrf/osrf_app_session.c b/src/libopensrf/osrf_app_session.c
index 0b5c6d6..c7b80d3 100644
--- a/src/libopensrf/osrf_app_session.c
+++ b/src/libopensrf/osrf_app_session.c
@@ -24,6 +24,9 @@ struct osrf_app_request_struct {
 	/** 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;
@@ -76,6 +79,7 @@ static osrfAppRequest* _osrf_app_request_init(
 	req->reset_timeout  = 0;
 	req->next           = NULL;
 	req->prev           = NULL;
+	req->part_response_buffer = NULL;
 
 	return req;
 }
@@ -98,6 +102,9 @@ static void _osrf_app_request_free( osrfAppRequest * req ) {
 			req->result = next_msg;
 		}
 
+        if (req->part_response_buffer)
+            buffer_free(req->part_response_buffer);
+
 		free( req );
 	}
 }
@@ -114,8 +121,57 @@ static void _osrf_app_request_push_queue( osrfAppRequest* req, osrfMessage* resu
 	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
 
diff --git a/src/libopensrf/osrf_application.c b/src/libopensrf/osrf_application.c
index c205214..03eb7a3 100644
--- a/src/libopensrf/osrf_application.c
+++ b/src/libopensrf/osrf_application.c
@@ -89,7 +89,7 @@
 /**
 	@brief Default size of output buffer.
 */
-#define OSRF_MSG_BUFFER_SIZE     10240
+#define OSRF_MSG_BUNDLE_SIZE     10240
 
 /**
 	@brief Represent an Application.
@@ -421,7 +421,8 @@ static osrfMethod* build_method( const char* methodName, const char* symbolName,
 	if(user_data)
 		method->userData    = user_data;
 
-	method->bufsize         = OSRF_MSG_BUFFER_SIZE;
+	method->max_bundle_size = OSRF_MSG_BUNDLE_SIZE;
+    method->max_chunk_size  = OSRF_MSG_CHUNK_SIZE;
 	return method;
 }
 
@@ -429,7 +430,7 @@ static osrfMethod* build_method( const char* methodName, const char* symbolName,
 	@brief Set the effective output buffer size for a given method.
 	@param appName Name of the application.
 	@param methodName Name of the method.
-	@param bufsize Desired size of the output buffer, in bytes.
+	@param max_bundle_size Desired size of the output buffer, in bytes.
 	@return Zero if successful, or -1 if the specified method cannot be found.
 
 	A smaller buffer size may result in a lower latency for the first response, since we don't
@@ -442,18 +443,18 @@ static osrfMethod* build_method( const char* methodName, const char* symbolName,
 	This function has no effect on atomic methods, because all responses are sent in a single
 	message anyway.  Likewise it has no effect on a method that returns only a single response.
 */
-int osrfMethodSetBufferSize( const char* appName, const char* methodName, size_t bufsize ) {
+int osrfMethodSetBundleSize( const char* appName, const char* methodName, size_t max_bundle_size ) {
 	osrfMethod* method = _osrfAppFindMethod( appName, methodName );
 	if( method ) {
 		osrfLogInfo( OSRF_LOG_MARK,
 			"Setting outbuf buffer size to %lu for method %s of application %s",
-			(unsigned long) bufsize, methodName, appName );
-		method->bufsize = bufsize;
+			(unsigned long) max_bundle_size, methodName, appName );
+		method->max_bundle_size = max_bundle_size;
 		return 0;
 	} else {
 		osrfLogWarning( OSRF_LOG_MARK,
 			"Unable to set outbuf buffer size to %lu for method %s of application %s",
-			(unsigned long) bufsize, methodName, appName );
+			(unsigned long) max_bundle_size, methodName, appName );
 		return -1;
 	}
 }
@@ -752,7 +753,7 @@ static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int
 
 			// 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( len_so_far && (strlen( json ) + len_so_far + 3 >= ctx->method->max_bundle_size )) {
 				if( flush_responses( ctx->session, ctx->session->outbuf ))
 					return -1;
 			}

commit 56e65d1e6fb4ee72b28b4e008b9461d5bac55b8d
Author: Bill Erickson <berick at esilibrary.com>
Date:   Mon Feb 24 15:14:19 2014 -0500

    LP#1612771: Perl max_chunk_size additions
    
    * Added missing max_chunk_size method to AppSession
    * Copy API max_chunk_size value into the handler AppRequest
    * Fix error where no-chunking resulted in empty responses
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/src/perl/lib/OpenSRF/AppSession.pm b/src/perl/lib/OpenSRF/AppSession.pm
index 7454970..ba3aa54 100644
--- a/src/perl/lib/OpenSRF/AppSession.pm
+++ b/src/perl/lib/OpenSRF/AppSession.pm
@@ -892,6 +892,13 @@ sub max_bundle_size {
 	return $self->{max_bundle_size};
 }
 
+sub max_chunk_size {
+	my $self = shift;
+	my $value = shift;
+	$self->{max_chunk_size} = $value if (defined($value));
+	return $self->{max_chunk_size};
+}
+
 sub recv_timeout {
 	my $self = shift;
 	my $timeout = shift;
@@ -1034,27 +1041,31 @@ sub respond {
 	my $msg = shift;
 	return unless ($self and $self->session and !$self->complete);
 
-
     my $type = 'RESULT';
 	my $response;
 	if (ref($msg) && UNIVERSAL::isa($msg, 'OpenSRF::DomainObject::oilsResponse')) {
 		$response = $msg;
         $type = 'STATUS' if UNIVERSAL::isa($response, 'OpenSRF::DomainObject::oilsStatus');
-	} elsif ($self->max_chunk_size > 0) { # we might need to chunk
-        my $str = OpenSRF::Utils::JSON->perl2JSON($msg);
-        if (length($str) > $self->max_chunk_size) { # send partials ("chunking")
-            for (my $i = 0; $i < length($str); $i += $self->max_chunk_size) {
-                $response = new OpenSRF::DomainObject::oilsResult::Partial;
-        		$response->content( substr($str, $i, $self->max_chunk_size) );
-	            $self->session->send($type, $response, $self->threadTrace);
+
+	} else {
+
+        if ($self->max_chunk_size > 0) { # we might need to chunk
+            my $str = OpenSRF::Utils::JSON->perl2JSON($msg);
+            if (length($str) > $self->max_chunk_size) { # send partials ("chunking")
+                for (my $i = 0; $i < length($str); $i += $self->max_chunk_size) {
+                    $response = new OpenSRF::DomainObject::oilsResult::Partial;
+                    $response->content( substr($str, $i, $self->max_chunk_size) );
+                    $self->session->send($type, $response, $self->threadTrace);
+                }
+                # This triggers reconstruction on the remote end
+                $response = new OpenSRF::DomainObject::oilsResult::PartialComplete;
+                return $self->session->send($type, $response, $self->threadTrace);
             }
-            # This triggers reconstruction on the remote end
-            $response = new OpenSRF::DomainObject::oilsResult::PartialComplete;
-	        return $self->session->send($type, $response, $self->threadTrace);
-        } else {
-            $response = new OpenSRF::DomainObject::oilsResult;
-            $response->content( $msg );
         }
+
+        # message failed to exceed max chunk size OR chunking disabled
+        $response = new OpenSRF::DomainObject::oilsResult;
+        $response->content($msg);
     }
 
     if ($self->{max_bundle_count} > 0 or $self->{max_bundle_size} > 0) { # we are bundling, and we need to test the size or count
diff --git a/src/perl/lib/OpenSRF/Application.pm b/src/perl/lib/OpenSRF/Application.pm
index 9749a1d..8aec164 100644
--- a/src/perl/lib/OpenSRF/Application.pm
+++ b/src/perl/lib/OpenSRF/Application.pm
@@ -65,7 +65,7 @@ sub max_chunk_size {
 	my $self = shift;
 	return 0 unless ref($self);
 	return $self->{max_chunk_size} if (defined($self->{max_chunk_size}));
-	return 2 * $self->max_bundle_size;
+	return 104858; # 1/10 MB
 }
 
 sub api_name {
@@ -182,6 +182,7 @@ sub handler {
 			my $appreq = OpenSRF::AppRequest->new( $session );
 			$appreq->max_bundle_size( $coderef->max_bundle_size );
 			$appreq->max_bundle_count( $coderef->max_bundle_count );
+			$appreq->max_chunk_size( $coderef->max_chunk_size );
 
 			$log->debug( "in_request = $in_request : [" . $appreq->threadTrace."]", INTERNAL );
 			if( $in_request ) {
diff --git a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
index 25d8f50..307eb57 100644
--- a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
+++ b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
@@ -13,7 +13,8 @@ BEGIN {
 					STATUS_NOTFOUND STATUS_NOTALLOWED STATUS_TIMEOUT
 					STATUS_INTERNALSERVERERROR STATUS_NOTIMPLEMENTED
 					STATUS_VERSIONNOTSUPPORTED STATUS_REDIRECTED 
-					STATUS_EXPFAILED STATUS_COMPLETE/;
+					STATUS_EXPFAILED STATUS_COMPLETE STATUS_PARTIAL
+					STATUS_NOCONTENT/;
 
 %EXPORT_TAGS = (
 	status => [ qw/STATUS_CONTINUE STATUS_OK STATUS_ACCEPTED
@@ -21,7 +22,8 @@ BEGIN {
 					STATUS_NOTFOUND STATUS_NOTALLOWED STATUS_TIMEOUT
 					STATUS_INTERNALSERVERERROR STATUS_NOTIMPLEMENTED
 					STATUS_VERSIONNOTSUPPORTED STATUS_REDIRECTED 
-					STATUS_EXPFAILED STATUS_COMPLETE/ ],
+					STATUS_EXPFAILED STATUS_COMPLETE STATUS_PARTIAL
+					STATUS_NOCONTENT/ ],
 );
 
 }
@@ -284,7 +286,10 @@ package OpenSRF::DomainObject::oilsResult::Partial;
 use OpenSRF::DomainObject::oilsResponse qw/:status/;
 use base 'OpenSRF::DomainObject::oilsResult';
 use vars qw/$status $statusCode/;
-OpenSRF::Utils::JSON->register_class_hint( hint => 'osrfResult', name => 'OpenSRF::DomainObject::oilsResult::Partial', type => 'hash' );
+OpenSRF::Utils::JSON->register_class_hint(
+    hint => 'osrfResultPartial',
+    name => 'OpenSRF::DomainObject::oilsResult::Partial',
+    type => 'hash');
 
 
 $status = 'Partial Response';
@@ -324,7 +329,10 @@ package OpenSRF::DomainObject::oilsResult::PartialComplete;
 use OpenSRF::DomainObject::oilsResponse qw/:status/;
 use base 'OpenSRF::DomainObject::oilsResult';
 use vars qw/$status $statusCode/;
-OpenSRF::Utils::JSON->register_class_hint( hint => 'osrfResult', name => 'OpenSRF::DomainObject::oilsResult::Partial', type => 'hash' );
+OpenSRF::Utils::JSON->register_class_hint( 
+    hint => 'osrfResultPartialComplete',
+    name => 'OpenSRF::DomainObject::oilsResult::PartialComplete',
+    type => 'hash');
 
 
 $status = 'Partial Response Finalized';

commit 01f95834835bed94df93a7fdad59e38486e6485a
Author: Mike Rylander <mrylander at gmail.com>
Date:   Sun Feb 23 14:51:13 2014 -0500

    LP#1612771: bundling and chunking
    
    This patch is first in a series of patches that provides the following
    features:
    
    * OpenSRF message bundling -- Pack multiple OpenSRF messages together
    in a single XMPP envelope, as long as we believe more messages will be
    sent in the future and we are below some threshold of combined message size.
    The default for that threshold is 25Kb.
    
     * OpenSRF message chunking -- Break up large OpenSRF messages across
    multiple XMPP envelopes. This is implemented with a new OpenSRF message type.
    C, Perl, and Javascript libraries are taught how to reconstruct chunked
    messages. The default chunking threshold is 50Kb, just a bit below the default
    ejabberd max stanza size of 64Kb.
    
    This patch in particular renames "chunking" to "bundling", then
    implements message splitting ("chunking") in Perl using two new
    oilsResult subclasses
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Galen Charlton <gmc at esilibrary.com>

diff --git a/src/perl/lib/OpenSRF/AppSession.pm b/src/perl/lib/OpenSRF/AppSession.pm
index 9e371c7..7454970 100644
--- a/src/perl/lib/OpenSRF/AppSession.pm
+++ b/src/perl/lib/OpenSRF/AppSession.pm
@@ -858,15 +858,17 @@ sub new {
 			payload			=> $payload,
 			complete		=> 0,
 			resp_count		=> 0,
-			max_chunk_count		=> 0,
-			current_chunk_count	=> 0,
+			max_bundle_count	=> 0,
+			current_bundle_count=> 0,
 			max_chunk_size		=> 0,
-			current_chunk_size	=> 0,
-			current_chunk		=> [],
+			max_bundle_size		=> 0,
+			current_bundle_size	=> 0,
+			current_bundle		=> [],
 			timeout_reset		=> 0,
 			recv_timeout		=> 30,
 			remaining_recv_timeout	=> 30,
 			recv_queue		=> [],
+			part_recv_buffer=> '',
 	};
 
 	bless $self => $class;
@@ -876,18 +878,18 @@ sub new {
 	return $self;
 }
 
-sub max_chunk_count {
+sub max_bundle_count {
 	my $self = shift;
 	my $value = shift;
-	$self->{max_chunk_count} = $value if (defined($value));
-	return $self->{max_chunk_count};
+	$self->{max_bundle_count} = $value if (defined($value));
+	return $self->{max_bundle_count};
 }
 
-sub max_chunk_size {
+sub max_bundle_size {
 	my $self = shift;
 	my $value = shift;
-	$self->{max_chunk_size} = $value if (defined($value));
-	return $self->{max_chunk_size};
+	$self->{max_bundle_size} = $value if (defined($value));
+	return $self->{max_bundle_size};
 }
 
 sub recv_timeout {
@@ -932,9 +934,17 @@ sub complete {
 	} else {
 		$self->session->queue_wait(0);
 	}
+    $self->completing(0) if ($self->{complete});
 	return $self->{complete};
 }
 
+sub completing {
+	my $self = shift;
+	my $value = shift;
+	$self->{_completing} = $value if (defined($value));
+	return $self->{_completing};
+}
+
 sub duration {
 	my $self = shift;
 	$self->wait_complete;
@@ -969,6 +979,18 @@ sub push_queue {
 		$self->complete(1);
 		#return; eventually...
 	}
+
+	if( UNIVERSAL::isa($resp, "OpenSRF::DomainObject::oilsResult::Partial")) {
+		$self->{part_recv_buffer} .= $resp->content;
+		return 1;
+	} elsif( UNIVERSAL::isa($resp, "OpenSRF::DomainObject::oilsResult::PartialComplete")) {
+		if ($self->{part_recv_buffer}) {
+			$resp = new OpenSRF::DomainObject::oilsResult;
+			$resp->content( OpenSRF::Utils::JSON->JSON2perl( $self->{part_recv_buffer} ) );
+			$self->{part_recv_buffer} = '';
+		} 
+	}
+
 	push @{ $self->{recv_queue} }, $resp;
 }
 
@@ -1012,35 +1034,50 @@ sub respond {
 	my $msg = shift;
 	return unless ($self and $self->session and !$self->complete);
 
+
+    my $type = 'RESULT';
 	my $response;
-	if (ref($msg) && UNIVERSAL::isa($msg, 'OpenSRF::DomainObject::oilsResult')) {
+	if (ref($msg) && UNIVERSAL::isa($msg, 'OpenSRF::DomainObject::oilsResponse')) {
 		$response = $msg;
-	} else {
-		$response = new OpenSRF::DomainObject::oilsResult;
-		$response->content($msg);
-	}
+        $type = 'STATUS' if UNIVERSAL::isa($response, 'OpenSRF::DomainObject::oilsStatus');
+	} elsif ($self->max_chunk_size > 0) { # we might need to chunk
+        my $str = OpenSRF::Utils::JSON->perl2JSON($msg);
+        if (length($str) > $self->max_chunk_size) { # send partials ("chunking")
+            for (my $i = 0; $i < length($str); $i += $self->max_chunk_size) {
+                $response = new OpenSRF::DomainObject::oilsResult::Partial;
+        		$response->content( substr($str, $i, $self->max_chunk_size) );
+	            $self->session->send($type, $response, $self->threadTrace);
+            }
+            # This triggers reconstruction on the remote end
+            $response = new OpenSRF::DomainObject::oilsResult::PartialComplete;
+	        return $self->session->send($type, $response, $self->threadTrace);
+        } else {
+            $response = new OpenSRF::DomainObject::oilsResult;
+            $response->content( $msg );
+        }
+    }
 
-    if ($self->{max_chunk_count} > 0 or $self->{max_chunk_size} > 0) { # we are chunking, and we need to test the size or count
+    if ($self->{max_bundle_count} > 0 or $self->{max_bundle_size} > 0) { # we are bundling, and we need to test the size or count
 
-        $self->{current_chunk_size} += length(OpenSRF::Utils::JSON->perl2JSON($response));
-        push @{$self->{current_chunk}}, $response;  
-        $self->{current_chunk_count}++;
+        $self->{current_bundle_size} += length(OpenSRF::Utils::JSON->perl2JSON($response));
+        push @{$self->{current_bundle}}, $type, $response;  
+        $self->{current_bundle_count}++;
 
-        if (
-                ($self->{max_chunk_size}  && $self->{current_chunk_size}  >= $self->{max_chunk_size} ) ||
-                ($self->{max_chunk_count} && $self->{current_chunk_count} >= $self->{max_chunk_count})
+        if ( $self->completing ||
+                ($self->{max_bundle_size}  && $self->{current_bundle_size}  >= $self->{max_bundle_size} ) ||
+                ($self->{max_bundle_count} && $self->{current_bundle_count} >= $self->{max_bundle_count})
         ) { # send chunk and reset
-            my $send_res = $self->session->send(( map { ('RESULT', $_) } @{$self->{current_chunk}} ), $self->threadTrace);
-            $self->{current_chunk} = [];
-            $self->{current_chunk_size} = 0;
-            $self->{current_chunk_count} = 0;
+            my $send_res = $self->session->send( @{$self->{current_bundle}}, $self->threadTrace);
+            $self->{current_bundle} = [];
+            $self->{current_bundle_size} = 0;
+            $self->{current_bundle_count} = 0;
             return $send_res;
         } else { # not at a chunk yet, just queue it up
             return $self->session->app_request( $self->threadTrace );
         }
     }
 
-	$self->session->send('RESULT', $response, $self->threadTrace);
+	$self->session->send($type, $response, $self->threadTrace);
 }
 
 sub respond_complete {
@@ -1048,23 +1085,15 @@ sub respond_complete {
 	my $msg = shift;
 	return unless ($self and $self->session and !$self->complete);
 
-    if (defined($msg)) {
-    	my $response;
-	    if (ref($msg) && UNIVERSAL::isa($msg, 'OpenSRF::DomainObject::oilsResult')) {
-		    $response = $msg;
-    	} else {
-	    	$response = new OpenSRF::DomainObject::oilsResult;
-		    $response->content($msg);
-    	}
-
-        push @{$self->{current_chunk}}, $response;
-    }
-
-	my $stat = OpenSRF::DomainObject::oilsConnectStatus->new(
-		statusCode => STATUS_COMPLETE(),
-		status => 'Request Complete' );
+    $self->respond($msg) if (defined($msg));
 
-	$self->session->send( ( map { ('RESULT', $_) } @{$self->{current_chunk}} ), 'STATUS' => $stat, $self->threadTrace);
+    $self->completing(1);
+    $self->respond(
+        OpenSRF::DomainObject::oilsConnectStatus->new(
+            statusCode => STATUS_COMPLETE(),
+            status => 'Request Complete'
+        )
+    );
 	$self->complete(1);
 }
 
@@ -1129,9 +1158,17 @@ sub complete {
 	my $x = shift;
 	my $c = shift;
 	$x->{complete} = $c if ($c);
+    $x->completing(0) if ($c);
 	return $x->{complete};
 }
 
+sub completing {
+	my $self = shift;
+	my $value = shift;
+	$self->{_completing} = $value if (defined($value));
+	return $self->{_completing};
+}
+
 sub status {}
 
 
diff --git a/src/perl/lib/OpenSRF/Application.pm b/src/perl/lib/OpenSRF/Application.pm
index 023bb8d..9749a1d 100644
--- a/src/perl/lib/OpenSRF/Application.pm
+++ b/src/perl/lib/OpenSRF/Application.pm
@@ -48,17 +48,24 @@ sub argc {
 	return $self->{argc};
 }
 
-sub max_chunk_size {
+sub max_bundle_size {
 	my $self = shift;
 	return 0 unless ref($self);
-	return $self->{max_chunk_size} if (defined($self->{max_chunk_size}));
+	return $self->{max_bundle_size} if (defined($self->{max_bundle_size}));
 	return 10240;
 }
 
-sub max_chunk_count {
+sub max_bundle_count {
+	my $self = shift;
+	return 0 unless ref($self);
+	return $self->{max_bundle_count} || 0;
+}
+
+sub max_chunk_size {
 	my $self = shift;
 	return 0 unless ref($self);
-	return $self->{max_chunk_count} || 0;
+	return $self->{max_chunk_size} if (defined($self->{max_chunk_size}));
+	return 2 * $self->max_bundle_size;
 }
 
 sub api_name {
@@ -173,8 +180,8 @@ sub handler {
 			my @args = $app_msg->params;
 			$coderef->session( $session );
 			my $appreq = OpenSRF::AppRequest->new( $session );
-			$appreq->max_chunk_size( $coderef->max_chunk_size );
-			$appreq->max_chunk_count( $coderef->max_chunk_count );
+			$appreq->max_bundle_size( $coderef->max_bundle_size );
+			$appreq->max_bundle_count( $coderef->max_bundle_count );
 
 			$log->debug( "in_request = $in_request : [" . $appreq->threadTrace."]", INTERNAL );
 			if( $in_request ) {
diff --git a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
index 18e2e3c..25d8f50 100644
--- a/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
+++ b/src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm
@@ -51,10 +51,13 @@ layer messages send between the client and server.
 
 sub STATUS_CONTINUE		{ return 100 }
 
-sub STATUS_OK				{ return 200 }
+sub STATUS_OK			{ return 200 }
 sub STATUS_ACCEPTED		{ return 202 }
 sub STATUS_COMPLETE		{ return 205 }
 
+sub STATUS_PARTIAL		{ return 206 }
+sub STATUS_NOCONTENT	{ return 204 }
+
 sub STATUS_REDIRECTED	{ return 307 }
 
 sub STATUS_BADREQUEST	{ return 400 }
@@ -277,6 +280,85 @@ B<OpenSRF::DomainObject::oilsResponse>
 
 #-------------------------------------------------------------------------------
 
+package OpenSRF::DomainObject::oilsResult::Partial;
+use OpenSRF::DomainObject::oilsResponse qw/:status/;
+use base 'OpenSRF::DomainObject::oilsResult';
+use vars qw/$status $statusCode/;
+OpenSRF::Utils::JSON->register_class_hint( hint => 'osrfResult', name => 'OpenSRF::DomainObject::oilsResult::Partial', type => 'hash' );
+
+
+$status = 'Partial Response';
+$statusCode = STATUS_PARTIAL;
+
+=head1 NAME
+
+OpenSRF::DomainObject::oilsResult::Partial
+
+=head1 SYNOPSIS
+
+This class is used internally to break apart large OpenSRF messages into small
+chunks, to reduce the maximum possible stanza size when sending a message over
+XMPP.
+
+=cut
+
+sub content {
+        my $self = shift;
+	my $val = shift;
+
+	$self->{content} = $val if (defined $val);
+	return $self->{content};
+}
+
+=head1 SEE ALSO
+
+B<OpenSRF::DomainObject::oilsResponse>
+
+=cut
+
+1;
+
+#-------------------------------------------------------------------------------
+
+package OpenSRF::DomainObject::oilsResult::PartialComplete;
+use OpenSRF::DomainObject::oilsResponse qw/:status/;
+use base 'OpenSRF::DomainObject::oilsResult';
+use vars qw/$status $statusCode/;
+OpenSRF::Utils::JSON->register_class_hint( hint => 'osrfResult', name => 'OpenSRF::DomainObject::oilsResult::Partial', type => 'hash' );
+
+
+$status = 'Partial Response Finalized';
+$statusCode = STATUS_NOCONTENT;
+
+=head1 NAME
+
+OpenSRF::DomainObject::oilsResult::Partial
+
+=head1 SYNOPSIS
+
+This class is used internally to mark the end of a stream of small partial
+OpenSRF messages of type OpenSRF::DomainObject::oilsResult::Partial.
+
+=cut
+
+sub content {
+        my $self = shift;
+	my $val = shift;
+
+	$self->{content} = $val if (defined $val);
+	return $self->{content};
+}
+
+=head1 SEE ALSO
+
+B<OpenSRF::DomainObject::oilsResponse>
+
+=cut
+
+1;
+
+#-------------------------------------------------------------------------------
+
 package OpenSRF::DomainObject::oilsException;
 use OpenSRF::DomainObject::oilsResponse qw/:status/;
 use OpenSRF::EX;

-----------------------------------------------------------------------

Summary of changes:
 README                                            |   23 ++--
 doc/Bundling-and-Chunking.txt                     |   19 +++
 doc/OpenSRF-Messaging-Protocol.html               |   10 ++-
 include/opensrf/osrf_app_session.h                |    6 +
 include/opensrf/osrf_application.h                |    5 +-
 include/opensrf/osrf_message.h                    |    3 +
 src/javascript/opensrf.js                         |   63 +++++++++-
 src/libopensrf/osrf_app_session.c                 |   56 +++++++++
 src/libopensrf/osrf_application.c                 |  135 +++++++++++++++-----
 src/libopensrf/osrf_message.c                     |    8 +-
 src/perl/lib/OpenSRF/AppSession.pm                |  126 +++++++++++++------
 src/perl/lib/OpenSRF/Application.pm               |   20 ++-
 src/perl/lib/OpenSRF/DomainObject/oilsResponse.pm |   96 ++++++++++++++-
 13 files changed, 465 insertions(+), 105 deletions(-)
 create mode 100644 doc/Bundling-and-Chunking.txt


hooks/post-receive
-- 
OpenSRF




More information about the opensrf-commits mailing list