Merge in touch.
[awesomized/libmemcached] / libmemcached / response.cc
index 1548b4ed23c847f1ad2a6f70d4680809803b959a..061f7401fee84a19dbd462a0564601ebce5a7276 100644 (file)
@@ -1,5 +1,5 @@
 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
- * 
+ *
  *  Libmemcached library
  *
  *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
@@ -36,6 +36,7 @@
  */
 
 #include <libmemcached/common.h>
+#include <libmemcached/string.hpp>
 
 static memcached_return_t textual_read_one_response(memcached_server_write_instance_st ptr,
                                                     char *buffer, size_t buffer_length,
@@ -70,7 +71,9 @@ memcached_return_t memcached_read_one_response(memcached_server_write_instance_s
            rc == MEMCACHED_PROTOCOL_ERROR or
            rc == MEMCACHED_CLIENT_ERROR or
            rc == MEMCACHED_MEMORY_ALLOCATION_FAILURE)
+  {
     memcached_io_reset(ptr);
+  }
 
   return rc;
 }
@@ -123,7 +126,9 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st
   ssize_t read_length= 0;
 
   if (ptr->root->flags.use_udp)
+  {
     return memcached_set_error(*ptr, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
+  }
 
   WATCHPOINT_ASSERT(ptr->root);
   end_ptr= buffer + MEMCACHED_DEFAULT_COMMAND_SIZE;
@@ -200,7 +205,6 @@ static memcached_return_t textual_value_fetch(memcached_server_write_instance_st
   /* We add two bytes so that we can walk the \r\n */
   if (memcached_failed(memcached_string_check(&result->value, value_length +2)))
   {
-    value_length= 0;
     return memcached_set_error(*ptr, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
   }
 
@@ -252,7 +256,9 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
                                                     char *buffer, size_t buffer_length,
                                                     memcached_result_st *result)
 {
-  memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length);
+  size_t total_read;
+  memcached_return_t rc= memcached_io_readline(ptr, buffer, buffer_length, total_read);
+
   if (memcached_failed(rc))
   {
     return rc;
@@ -278,6 +284,7 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
     }
   case 'O': /* OK */
     return MEMCACHED_SUCCESS;
+
   case 'S': /* STORED STATS SERVER_ERROR */
     {
       if (buffer[2] == 'A') /* STORED STATS */
@@ -287,8 +294,25 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
       }
       else if (buffer[1] == 'E') /* SERVER_ERROR */
       {
-        char *startptr= buffer + 13, *endptr= startptr;
+        if (total_read == memcached_literal_param_size("SERVER_ERROR"))
+        {
+          return MEMCACHED_SERVER_ERROR;
+        }
+
+        if (total_read > memcached_literal_param_size("SERVER_ERROR object too large for cache") and
+            (memcmp(buffer, memcached_literal_param("SERVER_ERROR object too large for cache")) == 0))
+        {
+          return MEMCACHED_E2BIG;
+        }
 
+        // Move past the basic error message and whitespace
+        char *startptr= buffer + memcached_literal_param_size("SERVER_ERROR");
+        if (startptr[0] == ' ')
+        {
+          startptr++;
+        }
+
+        char *endptr= startptr;
         while (*endptr != '\r' && *endptr != '\n') endptr++;
 
         return memcached_set_error(*ptr, MEMCACHED_SERVER_ERROR, MEMCACHED_AT, startptr, size_t(endptr - startptr));
@@ -309,9 +333,13 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
   case 'N': /* NOT_FOUND */
     {
       if (buffer[4] == 'F')
+      {
         return MEMCACHED_NOTFOUND;
+      }
       else if (buffer[4] == 'S')
+      {
         return MEMCACHED_NOTSTORED;
+      }
       else
       {
         WATCHPOINT_STRING(buffer);
@@ -321,11 +349,17 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
   case 'E': /* PROTOCOL ERROR or END */
     {
       if (buffer[1] == 'N')
+      {
         return MEMCACHED_END;
+      }
       else if (buffer[1] == 'R')
+      {
         return MEMCACHED_PROTOCOL_ERROR;
+      }
       else if (buffer[1] == 'X')
+      {
         return MEMCACHED_DATA_EXISTS;
+      }
       else
       {
         WATCHPOINT_STRING(buffer);
@@ -333,12 +367,25 @@ static memcached_return_t textual_read_one_response(memcached_server_write_insta
       }
 
     }
+  case 'T': /* TOUCHED */
+    {
+      if (buffer[1] == 'O' and buffer[2] == 'U' 
+          and buffer[3] == 'C' and buffer[4] == 'H' 
+          and buffer[5] == 'E' and buffer[6] == 'D')
+      {
+        return MEMCACHED_SUCCESS;
+      }
+    }
+    return MEMCACHED_UNKNOWN_READ_FAILURE;
+
   case 'I': /* CLIENT ERROR */
     /* We add back in one because we will need to search for END */
     memcached_server_response_increment(ptr);
     return MEMCACHED_ITEM;
+
   case 'C': /* CLIENT ERROR */
     return MEMCACHED_CLIENT_ERROR;
+
   default:
     {
       unsigned long long auto_return_value;
@@ -381,7 +428,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
   header.response.cas= memcached_ntohll(header.response.cas);
   uint32_t bodylen= header.response.bodylen;
 
-  if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS ||
+  if (header.response.status == PROTOCOL_BINARY_RESPONSE_SUCCESS or
       header.response.status == PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE)
   {
     switch (header.response.opcode)
@@ -492,15 +539,18 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
     case PROTOCOL_BINARY_CMD_APPEND:
     case PROTOCOL_BINARY_CMD_PREPEND:
     case PROTOCOL_BINARY_CMD_DELETE:
+    case PROTOCOL_BINARY_CMD_TOUCH:
       {
         WATCHPOINT_ASSERT(bodylen == 0);
         return MEMCACHED_SUCCESS;
       }
+
     case PROTOCOL_BINARY_CMD_NOOP:
       {
         WATCHPOINT_ASSERT(bodylen == 0);
         return MEMCACHED_END;
       }
+
     case PROTOCOL_BINARY_CMD_STAT:
       {
         if (bodylen == 0)
@@ -581,36 +631,45 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
     case PROTOCOL_BINARY_CMD_APPENDQ:
     case PROTOCOL_BINARY_CMD_PREPENDQ:
       return binary_read_one_response(ptr, buffer, buffer_length, result);
+
     default:
       break;
     }
   }
 
   rc= MEMCACHED_SUCCESS;
-  unlikely(header.response.status != 0)
+  if (header.response.status != 0)
+  {
     switch (header.response.status)
     {
     case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
       rc= MEMCACHED_NOTFOUND;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
       rc= MEMCACHED_DATA_EXISTS;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
       rc= MEMCACHED_NOTSTORED;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_E2BIG:
       rc= MEMCACHED_E2BIG;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_ENOMEM:
       rc= MEMCACHED_MEMORY_ALLOCATION_FAILURE;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE:
       rc= MEMCACHED_AUTH_CONTINUE;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
       rc= MEMCACHED_AUTH_FAILURE;
       break;
+
     case PROTOCOL_BINARY_RESPONSE_EINVAL:
     case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
     default:
@@ -618,6 +677,7 @@ static memcached_return_t binary_read_one_response(memcached_server_write_instan
       rc= MEMCACHED_PROTOCOL_ERROR;
       break;
     }
+  }
 
   return rc;
 }