APR_DECLARE(apr_status_t) stomp_read(stomp_connection *connection, stomp_frame **frame, apr_pool_t *pool) { apr_status_t rc; stomp_frame *f; f = apr_pcalloc(pool, sizeof(stomp_frame)); if( f == NULL ) return APR_ENOMEM; f->headers = apr_hash_make(pool); if( f->headers == NULL ) return APR_ENOMEM; #define CHECK_SUCCESS if( rc!=APR_SUCCESS ) { return rc; } // Parse the frame out. { char *p; int length; // Parse the command. rc = stomp_read_line(connection, &p, &length, pool); CHECK_SUCCESS; f->command = p; // Start parsing the headers. while( 1 ) { rc = stomp_read_line(connection, &p, &length, pool); CHECK_SUCCESS; // Done with headers if(length == 0) break; { // Parse the header line. char *p2; void *key; void *value; p2 = strstr(p,":"); if( p2 == NULL ) { // Expected at 1 : to delimit the key from the value. return APR_EGENERAL; } // Null terminate the key *p2=0; key = p; // The rest if the value. value = p2+1; // Insert key/value into hash table. apr_hash_set(f->headers, key, APR_HASH_KEY_STRING, value); } } // Check for content length { char* content_length = apr_hash_get(f->headers, "content-length", APR_HASH_KEY_STRING); if(content_length) { char endbuffer[2]; apr_size_t length = 2; f->body_length = atoi(content_length); f->body = apr_pcalloc(pool, f->body_length); rc = apr_socket_recv(connection->socket, f->body, &f->body_length); CHECK_SUCCESS; // Expect a \n after the end rc = apr_socket_recv(connection->socket, endbuffer, &length); CHECK_SUCCESS; if(length != 2 || endbuffer[0] != '\0' || endbuffer[1] != '\n') return APR_EGENERAL; } else { // The remainder of the buffer (including the \n at the end) is the body) rc = stomp_read_buffer(connection, &f->body, pool); CHECK_SUCCESS; } } } #undef CHECK_SUCCESS *frame = f; return APR_SUCCESS; }
apr_status_t stomp_read(stomp_connection *connection, stomp_frame **frame, apr_pool_t *pool) { apr_status_t rc; stomp_frame *f; btlogger_trace("stomp_read"); f = apr_pcalloc(pool, sizeof(stomp_frame)); if( f == NULL ) { btlogger_warn("stomp_read returning APR_ENONMEM"); return APR_ENOMEM; } f->headers = apr_hash_make(pool); if( f->headers == NULL ) { btlogger_warn("stomp_read returning 2nd APR_ENONMEM"); return APR_ENOMEM; } #define CHECK_SUCCESS if( rc!=APR_SUCCESS ) { return rc; } // Parse the frame out. { char *p; int length; // Parse the command. rc = stomp_read_line(connection, &p, &length, pool); CHECK_SUCCESS; btlogger_trace("Read the command %s", p); f->command = p; // Start parsing the headers. while( 1 ) { rc = stomp_read_line(connection, &p, &length, pool); CHECK_SUCCESS; btlogger_trace("Read a header: %s length: %d", p, length); // Done with headers if(length == 0) break; { // Parse the header line. char *p2; void *key; void *value; p2 = strstr(p,":"); if( p2 == NULL ) { // Expected at 1 : to delimit the key from the value. btlogger_warn("stomp_read returning APR_EGENERAL"); return APR_EGENERAL; } // Null terminate the key *p2=0; key = p; // The rest if the value. value = p2+1; // Insert key/value into hash table. btlogger_trace("Add key %s with value %s to stomp headers", key, value); apr_hash_set(f->headers, key, APR_HASH_KEY_STRING, value); } } // Check for content length { char* content_length = apr_hash_get(f->headers, "content-length", APR_HASH_KEY_STRING); if(content_length) { char endbuffer[2]; apr_size_t length = 2; apr_size_t bodysz; apr_size_t tlen = 0; // number of bytes read btlogger_debug("Content-length %s detected", content_length); bodysz = f->body_length = atoi(content_length); if ((f->body = apr_pcalloc(pool, f->body_length)) == NULL) { btlogger_warn("stomp_read insufficient memory for buffer"); return APR_ENOMEM; } /* * Cannot read the content in one go since network byte buffers are finite. * Keep reading from the socket until body_length bytes have been read. */ while (tlen < bodysz) { char *bp = f->body + tlen; apr_size_t len = bodysz - tlen; rc = apr_socket_recv(connection->socket, bp, &len); CHECK_SUCCESS; tlen += len; } // Expect a \n after the end rc = apr_socket_recv(connection->socket, endbuffer, &length); CHECK_SUCCESS; if(length != 2 || endbuffer[0] != '\0' || endbuffer[1] != '\n') { btlogger_warn("stomp_read returning 2nd APR_EGENERAL %d %c %c", length, endbuffer[0], endbuffer[1]); return APR_EGENERAL; } } else { btlogger_debug("No content-length detected"); // The remainder of the buffer (including the \n at the end) is the body) rc = stomp_read_buffer(connection, &f->body, pool); CHECK_SUCCESS; } } } #undef CHECK_SUCCESS *frame = f; return APR_SUCCESS; }