-void processInputBuffer(redisClient *c) {
-again:
- /* Before to process the input buffer, make sure the client is not
- * waitig for a blocking operation such as BLPOP. Note that the first
- * iteration the client is never blocked, otherwise the processInputBuffer
- * would not be called at all, but after the execution of the first commands
- * in the input buffer the client may be blocked, and the "goto again"
- * will try to reiterate. The following line will make it return asap. */
- if (c->flags & REDIS_BLOCKED || c->flags & REDIS_IO_WAIT) return;
- if (c->bulklen == -1) {
- /* Read the first line of the query */
- char *p = strchr(c->querybuf,'\n');
- size_t querylen;
-
- if (p) {
- sds query, *argv;
- int argc, j;
-
- query = c->querybuf;
- c->querybuf = sdsempty();
- querylen = 1+(p-(query));
- if (sdslen(query) > querylen) {
- /* leave data after the first line of the query in the buffer */
- c->querybuf = sdscatlen(c->querybuf,query+querylen,sdslen(query)-querylen);
- }
- *p = '\0'; /* remove "\n" */
- if (*(p-1) == '\r') *(p-1) = '\0'; /* and "\r" if any */
- sdsupdatelen(query);
-
- /* Now we can split the query in arguments */
- argv = sdssplitlen(query,sdslen(query)," ",1,&argc);
- sdsfree(query);
-
- if (c->argv) zfree(c->argv);
- c->argv = zmalloc(sizeof(robj*)*argc);
-
- for (j = 0; j < argc; j++) {
- if (sdslen(argv[j])) {
- c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
- c->argc++;
- } else {
- sdsfree(argv[j]);
+int processInlineBuffer(redisClient *c) {
+ char *newline = strstr(c->querybuf,"\r\n");
+ int argc, j;
+ sds *argv;
+ size_t querylen;
+
+ /* Nothing to do without a \r\n */
+ if (newline == NULL)
+ return REDIS_ERR;
+
+ /* Split the input buffer up to the \r\n */
+ querylen = newline-(c->querybuf);
+ argv = sdssplitlen(c->querybuf,querylen," ",1,&argc);
+
+ /* Leave data after the first line of the query in the buffer */
+ c->querybuf = sdsrange(c->querybuf,querylen+2,-1);
+
+ /* Setup argv array on client structure */
+ if (c->argv) zfree(c->argv);
+ c->argv = zmalloc(sizeof(robj*)*argc);
+
+ /* Create redis objects for all arguments. */
+ for (c->argc = 0, j = 0; j < argc; j++) {
+ if (sdslen(argv[j])) {
+ c->argv[c->argc] = createObject(REDIS_STRING,argv[j]);
+ c->argc++;
+ } else {
+ sdsfree(argv[j]);
+ }
+ }
+ zfree(argv);
+ return REDIS_OK;
+}
+
+/* Helper function. Trims query buffer to make the function that processes
+ * multi bulk requests idempotent. */
+static void setProtocolError(redisClient *c, int pos) {
+ c->flags |= REDIS_CLOSE_AFTER_REPLY;
+ c->querybuf = sdsrange(c->querybuf,pos,-1);
+}
+
+int processMultibulkBuffer(redisClient *c) {
+ char *newline = NULL;
+ char *eptr;
+ int pos = 0, tolerr;
+ long bulklen;
+
+ if (c->multibulklen == 0) {
+ /* The client should have been reset */
+ redisAssert(c->argc == 0);
+
+ /* Multi bulk length cannot be read without a \r\n */
+ newline = strstr(c->querybuf,"\r\n");
+ if (newline == NULL)
+ return REDIS_ERR;
+
+ /* We know for sure there is a whole line since newline != NULL,
+ * so go ahead and find out the multi bulk length. */
+ redisAssert(c->querybuf[0] == '*');
+ c->multibulklen = strtol(c->querybuf+1,&eptr,10);
+ pos = (newline-c->querybuf)+2;
+ if (c->multibulklen <= 0) {
+ c->querybuf = sdsrange(c->querybuf,pos,-1);
+ return REDIS_OK;
+ } else if (c->multibulklen > 1024*1024) {
+ addReplyError(c,"Protocol error: invalid multibulk length");
+ setProtocolError(c,pos);
+ return REDIS_ERR;
+ }
+
+ /* Setup argv array on client structure */
+ if (c->argv) zfree(c->argv);
+ c->argv = zmalloc(sizeof(robj*)*c->multibulklen);
+
+ /* Search new newline */
+ newline = strstr(c->querybuf+pos,"\r\n");
+ }
+
+ redisAssert(c->multibulklen > 0);
+ while(c->multibulklen) {
+ /* Read bulk length if unknown */
+ if (c->bulklen == -1) {
+ newline = strstr(c->querybuf+pos,"\r\n");
+ if (newline != NULL) {
+ if (c->querybuf[pos] != '$') {
+ addReplyErrorFormat(c,
+ "Protocol error: expected '$', got '%c'",
+ c->querybuf[pos]);
+ setProtocolError(c,pos);
+ return REDIS_ERR;