From df38819f1831e769d714ee59c4f0480bf7504f4c Mon Sep 17 00:00:00 2001
From: Marc Hoersken <info@marc-hoersken.de>
Date: Wed, 20 Jun 2012 07:49:34 +0200
Subject: [PATCH] schannel: Implement new buffer size strategy

Increase decrypted and encrypted cache buffers using limitted
doubling strategy. More information on the mailinglist:
http://curl.haxx.se/mail/lib-2012-06/0255.html
---
 lib/curl_schannel.c |   38 +++++++++++++++++++++++++++++---------
 lib/curl_schannel.h |    7 +++++--
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c
index 93af113..b881fa6 100644
--- a/lib/curl_schannel.c
+++ b/lib/curl_schannel.c
@@ -307,13 +307,18 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
   }
 
   /* if we need a bigger buffer to read a full message, increase buffer now */
-  if(connssl->encdata_offset == connssl->encdata_length) {
-    if(connssl->encdata_length >= CURL_SCHANNEL_BUFFER_INIT_SIZE * 16)
+  if(connssl->encdata_length - connssl->encdata_offset <
+     CURL_SCHANNEL_BUFFER_FREE_SIZE) {
+    if(connssl->encdata_length >= CURL_SCHANNEL_BUFFER_MAX_SIZE) {
+      failf(data, "schannel: memory buffer size limit reached");
       return CURLE_OUT_OF_MEMORY;
+    }
+
     /* increase internal encrypted data buffer */
-    connssl->encdata_length *= 2;
+    connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
     connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                       connssl->encdata_length);
+
     if(connssl->encdata_buffer == NULL) {
       failf(data, "schannel: unable to re-allocate memory");
       return CURLE_OUT_OF_MEMORY;
@@ -824,17 +829,25 @@ schannel_recv(struct connectdata *conn, int sockindex,
     connssl->decdata_buffer = malloc(connssl->decdata_length);
     if(connssl->decdata_buffer == NULL) {
       failf(data, "schannel: unable to allocate memory");
-      return CURLE_OUT_OF_MEMORY;
+      *err = CURLE_OUT_OF_MEMORY;
+      return -1;
     }
   }
 
   /* increase buffer in order to fit the requested amount of data */
   while(connssl->encdata_length - connssl->encdata_offset <
-        CURL_SCHANNEL_BUFFER_STEP_SIZE || connssl->encdata_length < len) {
+        CURL_SCHANNEL_BUFFER_FREE_SIZE || connssl->encdata_length < len) {
+    if(connssl->encdata_length >= CURL_SCHANNEL_BUFFER_MAX_SIZE) {
+      failf(data, "schannel: memory buffer size limit reached");
+      *err = CURLE_OUT_OF_MEMORY;
+      return -1;
+    }
+
     /* increase internal encrypted data buffer */
-    connssl->encdata_length += CURL_SCHANNEL_BUFFER_STEP_SIZE;
+    connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
     connssl->encdata_buffer = realloc(connssl->encdata_buffer,
                                       connssl->encdata_length);
+
     if(connssl->encdata_buffer == NULL) {
       failf(data, "schannel: unable to re-allocate memory");
       *err = CURLE_OUT_OF_MEMORY;
@@ -899,14 +912,21 @@ schannel_recv(struct connectdata *conn, int sockindex,
               inbuf[1].cbBuffer);
 
         /* increase buffer in order to fit the received amount of data */
-        size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_STEP_SIZE ?
-               inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_STEP_SIZE;
+        size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
+               inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
         while(connssl->decdata_length - connssl->decdata_offset < size ||
               connssl->decdata_length < len) {
+          if(connssl->decdata_length >= CURL_SCHANNEL_BUFFER_MAX_SIZE) {
+            failf(data, "schannel: memory buffer size limit reached");
+            *err = CURLE_OUT_OF_MEMORY;
+            return -1;
+          }
+
           /* increase internal decrypted data buffer */
-          connssl->decdata_length += size;
+          connssl->decdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
           connssl->decdata_buffer = realloc(connssl->decdata_buffer,
                                             connssl->decdata_length);
+
           if(connssl->decdata_buffer == NULL) {
             failf(data, "schannel: unable to re-allocate memory");
             *err = CURLE_OUT_OF_MEMORY;
diff --git a/lib/curl_schannel.h b/lib/curl_schannel.h
index 7cdd2d1..4f48f16 100644
--- a/lib/curl_schannel.h
+++ b/lib/curl_schannel.h
@@ -95,12 +95,15 @@
 
 #ifdef BUFSIZE
 #define CURL_SCHANNEL_BUFFER_INIT_SIZE  BUFSIZE
-#define CURL_SCHANNEL_BUFFER_STEP_SIZE  BUFSIZE/2
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE  BUFSIZE/2
 #else
 #define CURL_SCHANNEL_BUFFER_INIT_SIZE  4096
-#define CURL_SCHANNEL_BUFFER_STEP_SIZE  2048
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE  2048
 #endif
 
+#define CURL_SCHANNEL_BUFFER_MAX_SIZE     CURL_SCHANNEL_BUFFER_INIT_SIZE*16
+#define CURL_SCHANNEL_BUFFER_STEP_FACTOR  2
+
 
 CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
 
-- 
1.7.10.msysgit.1

