php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | |
Patch stomp-patch-content-length for stomp Bug #64670Patch version 2013-05-06 21:20 UTC Return to Bug #64670 | Download this patchThis patch renders other patches obsolete Obsolete patches: Patch Revisions: 2013-05-06 21:20 UTC | 2013-05-06 15:35 UTC | 2013-04-18 18:41 UTCDeveloper: mi+php@aldan.algebra.com--- stomp.h 2012-11-18 17:35:40.000000000 -0500 +++ stomp.h 2013-05-03 17:19:36.000000000 -0400 @@ -82,7 +82,9 @@ +++ stomp.h 2013-05-06 12:26:05.000000000 -0400 @@ -74,4 +74,5 @@ #endif stomp_frame_cell_t *buffer; + char lead; } stomp_t; @@ -82,7 +83,9 @@ stomp_frame_t *stomp_read_frame(stomp_t *connection); int stomp_valid_receipt(stomp_t *connection, stomp_frame_t *frame); -int stomp_select(stomp_t *connection); -void stomp_set_error(stomp_t *stomp, const char *error, int errnum, const char *details); void stomp_free_frame(stomp_frame_t *frame); + +#define stomp_select(s) stomp_select_ex(s, s->options.read_timeout_sec, s->options.read_timeout_usec) #endif /* _STOMP_H_ */ --- stomp.c 2012-11-18 17:35:40.000000000 -0500 +++ stomp.c 2013-05-03 16:28:18.000000000 -0400 @@ -36,5 +36,6 @@ +++ stomp.c 2013-05-06 13:42:27.000000000 -0400 @@ -24,5 +24,4 @@ #include "php.h" -#include "zend_exceptions.h" #include "ext/standard/php_smart_str.h" #include "stomp.h" @@ -32,9 +31,9 @@ ZEND_EXTERN_MODULE_GLOBALS(stomp); -extern zend_class_entry *stomp_ce_exception; /* {{{ stomp_init */ -stomp_t *stomp_init() +stomp_t * +stomp_init() { /* Memory allocation */ @@ -67,5 +68,6 @@ @@ -61,4 +60,5 @@ stomp->buffer = NULL; + stomp->lead = '\0'; return stomp; } @@ -67,5 +67,6 @@ /* {{{ stomp_frame_buffer_push */ */ -void stomp_frame_buffer_push(stomp_frame_cell_t **pcell, stomp_frame_t *frame) +static void +stomp_frame_buffer_push(stomp_frame_cell_t **pcell, stomp_frame_t *frame) { stomp_frame_cell_t *cell = (stomp_frame_cell_t *) emalloc(sizeof(stomp_frame_cell_t)); @@ -85,5 +87,6 @@ @@ -85,5 +86,6 @@ /* {{{ stomp_frame_buffer_shift */ -stomp_frame_t *stomp_frame_buffer_shift(stomp_frame_cell_t **pcell) { +static stomp_frame_t * +stomp_frame_buffer_shift(stomp_frame_cell_t **pcell) { stomp_frame_t *frame = NULL; stomp_frame_t *frame = NULL; if (*pcell) { @@ -99,18 +102,24 @@ @@ -99,18 +101,24 @@ /* {{{ stomp_frame_buffer_clear */ -void stomp_frame_buffer_clear(stomp_frame_cell_t **pcell) { +static void - } + } if (stomp->error_details != NULL) { efree(stomp->error_details); @@ -121,13 +130,26 @@ @@ -121,13 +129,26 @@ stomp->error = estrdup(error); } - if (details != NULL) { - stomp->error_details = estrdup(details); + va_end(ap); + if (len < STOMP_BUFSIZE) /* shrink the buffer down */ + stomp->error_details = + erealloc(stomp->error_details, len + 1); } } /* }}} */ } } /* }}} */ -/* {{{ stomp_writeable +/* {{{ stomp_writeable */ -int stomp_writeable(stomp_t *stomp) +static int +stomp_writeable(stomp_t *stomp) { int n; @@ -147,7 +169,8 @@ @@ -147,7 +168,8 @@ /* }}} */ -/* {{{ stomp_connect +/* {{{ stomp_connect +int +stomp_connect(stomp_t *stomp, const char *host, unsigned short port TSRMLS_DC) { char error[1024]; @@ -159,5 +182,5 @@ @@ -159,5 +181,5 @@ efree(stomp->host); } - stomp->host = (char *) emalloc(strlen(host) + 1); + stomp->host = emalloc(strlen(host) + 1); memcpy(stomp->host, host, strlen(host)); stomp->host[strlen(host)] = '\0'; @@ -171,5 +194,5 @@ @@ -171,5 +193,5 @@ if (stomp->fd == -1) { snprintf(error, sizeof(error), "Unable to connect to %s:%ld", stomp->host, stomp->port); - stomp_set_error(stomp, error, errno, NULL); + stomp_set_error(stomp, error, errno, "%s", strerror(errno)); return 0; } @@ -179,6 +202,6 @@ @@ -179,6 +201,6 @@ if (getsockname(stomp->fd, (struct sockaddr*) &stomp->localaddr, &size) == -1) { snprintf(error, sizeof(error), "getsockname failed: %s (%d)", strerror(errno), errno); - stomp_set_error(stomp, error, errno, NULL); - return 0; + stomp_set_error(stomp, error, errno, NULL); + return 0; } @@ -187,4 +210,6 @@ @@ -187,4 +209,6 @@ if (stomp->options.use_ssl) { SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method()); + int ret; + + if (NULL == ctx) { stomp_set_error(stomp, "failed to create the SSL context", 0, NULL); @@ -200,18 +225,19 @@ @@ -200,18 +224,19 @@ return 0; } - + - stomp_set_error(stomp, error, errno, NULL); + stomp_set_error(stomp, error, errno, "%s", strerror(errno)); return 0; } @@ -221,5 +247,6 @@ @@ -221,5 +246,6 @@ /* {{{ stomp_close */ -void stomp_close(stomp_t *stomp) +void +stomp_close(stomp_t *stomp) { { if (NULL == stomp) { @@ -254,7 +281,8 @@ @@ -254,7 +280,8 @@ /* {{{ stomp_send */ -int stomp_send(stomp_t *stomp, stomp_frame_t *frame TSRMLS_DC) +int +stomp_send(stomp_t *stomp, stomp_frame_t *frame TSRMLS_DC) { - smart_str buf = {0}; + smart_str buf = { .c = NULL }; /* Command */ @@ -265,15 +293,15 @@ @@ -265,15 +292,15 @@ if (frame->headers) { - char *key; + char *key; - if (zend_hash_get_current_data(frame->headers, (void **)&value) == SUCCESS) { + if (zend_hash_get_current_data(frame->headers, &value) == SUCCESS) { smart_str_appends(&buf, value); } @@ -293,13 +321,11 @@ @@ -293,13 +320,11 @@ smart_str_appendc(&buf, '\n'); - if (frame->body > 0) { + if (frame->body) { smart_str_free(&buf); + stomp_set_error(stomp, "Unable to send data", errno, "%s", strerror(errno)); return 0; } @@ -307,23 +333,23 @@ @@ -307,23 +332,23 @@ #ifdef HAVE_STOMP_SSL if (stomp->options.use_ssl) { - if (-1 == SSL_write(stomp->ssl_handle, buf.c, buf.len) || -1 == SSL_write(stomp->ssl_handle, "\0\n", 2)) { - char error[1024]; -#endif +#endif smart_str_free(&buf); @@ -335,5 +361,6 @@ @@ -335,5 +360,6 @@ /* {{{ stomp_recv */ -int stomp_recv(stomp_t *stomp, char *msg, size_t length) +static int +stomp_recv(stomp_t *stomp, char *msg, size_t length) { int len; @@ -349,8 +376,23 @@ @@ -349,8 +375,23 @@ #endif - if (len == 0) { - TSRMLS_FETCH(); + stomp->status = -1; + break; } return len; @@ -358,55 +400,68 @@ @@ -358,55 +399,68 @@ /* }}} */ -/* {{{ stomp_read_buffer +/* {{{ stomp_recv_full - } - break; - } + if (buffer[i] == '\0') + break; - if (i >= bufsize) { - buffer = (char *) erealloc(buffer, bufsize + STOMP_BUFSIZE); + break; - if (i >= bufsize) { - buffer = (char *) erealloc(buffer, bufsize + STOMP_BUFSIZE); - bufsize += STOMP_BUFSIZE; - } + i++; return -1; } + } else + efree(buffer); - memcpy(*data, buffer, i); - } - - efree(buffer); - return i-1; + return i; } /* }}} */ @@ -414,15 +469,14 @@ @@ -414,15 +468,24 @@ /* {{{ stomp_read_line */ -static int stomp_read_line(stomp_t *stomp, char **data) +static int size_t bufsize = STOMP_BUFSIZE + 1; - char *buffer = (char *) emalloc(STOMP_BUFSIZE + 1); + char *buffer = emalloc(STOMP_BUFSIZE + 1); while (1) { - - while (1) { + /* + * While skipping the trailing newlines from the previous frame, + * we may have stumbled upon the first byte of this one. + */ + if (stomp->lead != '\0') { + buffer[i++] = stomp->lead; + stomp->lead = '\0'; + drain = 0; + } - size_t length = 1; - rc = stomp_recv(stomp, buffer + i, length); + while (1) { + rc = stomp_recv(stomp, buffer + i, 1); if (rc < 1) { efree(buffer); @@ -430,36 +484,41 @@ @@ -430,36 +493,35 @@ } - if (1 == length) { - i++; + if (buffer[i] == '\n') { + /* + * Drain leading newlines, if any, that the STOMP + * protocol allows after the nul-byte of an earlier + * frame: + * http://stomp.github.io/stomp-specification-1.1.html + */ + if (drain) + continue; + buffer[i] = '\0'; + break; - break; - } else if (buffer[i-1] == 0) { - efree(buffer); - return 0; - } - } + i++; - if (i >= bufsize) { - buffer = (char *) erealloc(buffer, bufsize + STOMP_BUFSIZE); - } + if (i >= bufsize) { + buffer = erealloc(buffer, bufsize + STOMP_BUFSIZE); + bufsize += STOMP_BUFSIZE; } } - } - if (i > 1) { - return i-1; + return i; } /* }}} */ @@ -467,5 +526,6 @@ @@ -467,5 +529,6 @@ /* {{{ stomp_free_frame */ -void stomp_free_frame(stomp_frame_t *frame) +void +stomp_free_frame(stomp_frame_t *frame) { if (frame) { @@ -485,11 +545,13 @@ @@ -485,11 +548,13 @@ /* }}} */ -/* {{{ stomp_read_frame +/* {{{ stomp_read_frame { stomp_frame_t *f = NULL; - char *cmd = NULL, *length_str = NULL; - int length = 0; + char *cmd = NULL; + char *cmd; + int length; + char endbyte; if (stomp->buffer) { @@ -498,4 +560,9 @@ @@ -498,4 +563,9 @@ if (!stomp_select(stomp)) { + stomp_set_error(stomp, "Timeout", 0, "No data available " + "within the specified timeout ", + stomp->options.read_timeout_sec, + stomp->options.read_timeout_sec); return NULL; } @@ -507,6 +574,8 @@ @@ -507,6 +577,8 @@ } + f->body_length = -1; + - length = stomp_read_line(stomp, &cmd); + length = stomp_read_line(stomp, &cmd, 1); if (length < 1) { RETURN_READ_FRAME_FAIL; @@ -518,54 +587,91 @@ @@ -518,57 +590,96 @@ /* Parse the header */ while (1) { - char *p = NULL; - length = stomp_read_line(stomp, &p); + break; + case -1: /* Content-length not found among the headers */ f->body_length = stomp_read_buffer(stomp, &f->body); } @@ -577,10 +683,10 @@ + stomp_select_ex(stomp, 0, 0); /* Drain any newlines already here */ + return f; } @@ -577,10 +688,10 @@ /* {{{ stomp_valid_receipt */ -int stomp_valid_receipt(stomp_t *stomp, stomp_frame_t *frame) { +int - if (zend_hash_find(frame->headers, "receipt", sizeof("receipt"), (void **)&receipt) == SUCCESS) { + if (zend_hash_find(frame->headers, "receipt", sizeof("receipt"), &receipt) == SUCCESS) { stomp_frame_cell_t *buffer = NULL; success = 0; @@ -589,12 +695,11 @@ @@ -589,12 +700,11 @@ if (res) { if (0 == strncmp("RECEIPT", res->command, sizeof("RECEIPT") - 1)) { - char *receipt_id = NULL; - if (zend_hash_find(res->headers, "receipt-id", sizeof("receipt-id"), (void **)&receipt_id) == SUCCESS - stomp_set_error(stomp, error, 0, NULL); + stomp_set_error(stomp, "Unexpected receipt id", 0, "%s", receipt_id); } stomp_free_frame(res); @@ -602,8 +707,8 @@ @@ -602,8 +712,8 @@ return success; } else if (0 == strncmp("ERROR", res->command, sizeof("ERROR") - 1)) { - char *error_msg = NULL; - if (zend_hash_find(res->headers, "message", sizeof("message"), (void **)&error_msg) == SUCCESS) { - } + void *error_msg = NULL; + zend_hash_find(res->headers, "message", sizeof("message"), &error_msg); + stomp_set_error(stomp, error_msg ? error_msg : "ERROR", 0, + res->body ? "%s" : NULL, res->body); + "%s", res->body ? res->body : "zhopa"); stomp_free_frame(res); stomp->buffer = buffer; @@ -624,5 +729,6 @@ @@ -624,27 +734,45 @@ /* {{{ stomp_select */ -int stomp_select(stomp_t *stomp) +int +stomp_select_ex(stomp_t *stomp, long sec, long usec) { int n; @@ -633,14 +739,14 @@ } struct timeval tv; - if (stomp->buffer) { + if (stomp->buffer || stomp->lead != '\0') { return 1; } - tv.tv_sec = stomp->options.read_timeout_sec; - tv.tv_usec = stomp->options.read_timeout_usec; + tv.tv_sec = sec; + tv.tv_usec = usec; + /* + * STOMP 1.1 spec says, there may be any number of newlines between + * frames. Though we tried to drain as many as have already arrived + * when we were finishing the processing of the previous frame, more + * may have come since then... So, before confirming, there is another + * frame pending, we have to ensure, the socket is not just readable, + * but that it has something other than newlines waiting in it... + */ + for (;;) { + char byte; n = php_pollfd_for(stomp->fd, PHP_POLLREADABLE, &tv); if (n < 1) { - n = php_pollfd_for(stomp->fd, PHP_POLLREADABLE, &tv); - if (n < 1) { + switch (php_pollfd_for(stomp->fd, PHP_POLLREADABLE, &tv)) { + case -1: + return 0; + case 0: #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK)) - if (n == 0) { + if (n == 0) { errno = ETIMEDOUT; - } -#endif + } - return 0; +#endif return 0; + return 0; + case 1: + if (stomp_recv(stomp, &byte, 1) < 1) + return 0; + if (byte == '\n') + continue; + stomp->lead = byte; + return 1; + } } - - return 1; } + /* }}} */ |
Copyright © 2001-2024 The PHP Group All rights reserved. |
Last updated: Sun May 05 11:01:33 2024 UTC |