Parcourir la source

Fixed mg_upload() and some SSL related issues

Sergey Lyubka il y a 12 ans
Parent
commit
b589e0cdf4
1 fichiers modifiés avec 79 ajouts et 126 suppressions
  1. 79 126
      mongoose.c

+ 79 - 126
mongoose.c

@@ -139,6 +139,7 @@ typedef long off_t;
 #define flockfile(x) EnterCriticalSection(&global_log_file_lock)
 #define flockfile(x) EnterCriticalSection(&global_log_file_lock)
 #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
 #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
 #define sleep(x) Sleep((x) * 1000)
 #define sleep(x) Sleep((x) * 1000)
+#define va_copy(x, y) x = y
 
 
 #if !defined(fileno)
 #if !defined(fileno)
 #define fileno(x) _fileno(x)
 #define fileno(x) _fileno(x)
@@ -296,45 +297,15 @@ typedef int socklen_t;
 
 
 static const char *http_500_error = "Internal Server Error";
 static const char *http_500_error = "Internal Server Error";
 
 
-// Snatched from OpenSSL includes. I put the prototypes here to be independent
-// from the OpenSSL source installation. Having this, mongoose + SSL can be
-// built on any system with binary SSL libraries installed.
+#if defined(NO_SSL_DL)
+#include <openssl/ssl.h>
+#else
+// SSL loaded dynamically from DLL.
+// I put the prototypes here to be independent from OpenSSL source installation.
 typedef struct ssl_st SSL;
 typedef struct ssl_st SSL;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_ctx_st SSL_CTX;
 typedef struct ssl_ctx_st SSL_CTX;
 
 
-#define SSL_ERROR_WANT_READ 2
-#define SSL_ERROR_WANT_WRITE 3
-#define SSL_FILETYPE_PEM 1
-#define CRYPTO_LOCK  1
-
-#if defined(NO_SSL_DL)
-extern void SSL_free(SSL *);
-extern int SSL_accept(SSL *);
-extern int SSL_connect(SSL *);
-extern int SSL_read(SSL *, void *, int);
-extern int SSL_write(SSL *, const void *, int);
-extern int SSL_get_error(const SSL *, int);
-extern int SSL_set_fd(SSL *, int);
-extern int SSL_pending(SSL *);
-extern SSL *SSL_new(SSL_CTX *);
-extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
-extern SSL_METHOD *SSLv23_server_method(void);
-extern SSL_METHOD *SSLv23_client_method(void);
-extern int SSL_library_init(void);
-extern void SSL_load_error_strings(void);
-extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
-extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
-extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
-extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
-extern void SSL_CTX_free(SSL_CTX *);
-extern unsigned long ERR_get_error(void);
-extern char *ERR_error_string(unsigned long, char *);
-extern int CRYPTO_num_locks(void);
-extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
-extern void CRYPTO_set_id_callback(unsigned long (*)(void));
-#else
-// Dynamically loaded SSL functionality
 struct ssl_func {
 struct ssl_func {
   const char *name;   // SSL function name
   const char *name;   // SSL function name
   void  (*ptr)(void); // Function pointer
   void  (*ptr)(void); // Function pointer
@@ -363,6 +334,7 @@ struct ssl_func {
   (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
   (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
 #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
 #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
 #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
 #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
+#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
 
 
 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
 #define CRYPTO_set_locking_callback \
 #define CRYPTO_set_locking_callback \
@@ -396,6 +368,7 @@ static struct ssl_func ssl_sw[] = {
   {"SSL_CTX_use_certificate_chain_file", NULL},
   {"SSL_CTX_use_certificate_chain_file", NULL},
   {"SSLv23_client_method", NULL},
   {"SSLv23_client_method", NULL},
   {"SSL_pending", NULL},
   {"SSL_pending", NULL},
+  {"SSL_CTX_set_verify", NULL},
   {NULL,    NULL}
   {NULL,    NULL}
 };
 };
 
 
@@ -494,7 +467,6 @@ static const char *config_options[] = {
 struct mg_context {
 struct mg_context {
   volatile int stop_flag;       // Should we stop event loop
   volatile int stop_flag;       // Should we stop event loop
   SSL_CTX *ssl_ctx;             // SSL context
   SSL_CTX *ssl_ctx;             // SSL context
-  SSL_CTX *client_ssl_ctx;      // Client SSL context
   char *config[NUM_OPTIONS];    // Mongoose configuration parameters
   char *config[NUM_OPTIONS];    // Mongoose configuration parameters
   mg_callback_t user_callback;  // User-defined callback function
   mg_callback_t user_callback;  // User-defined callback function
   void *user_data;              // User-defined data
   void *user_data;              // User-defined data
@@ -517,6 +489,7 @@ struct mg_connection {
   struct mg_request_info request_info;
   struct mg_request_info request_info;
   struct mg_context *ctx;
   struct mg_context *ctx;
   SSL *ssl;                   // SSL descriptor
   SSL *ssl;                   // SSL descriptor
+  SSL_CTX *client_ssl_ctx;    // SSL context for client connections
   struct socket client;       // Connected client
   struct socket client;       // Connected client
   time_t birth_time;          // Time when request was received
   time_t birth_time;          // Time when request was received
   int64_t num_bytes_sent;     // Total bytes sent to client
   int64_t num_bytes_sent;     // Total bytes sent to client
@@ -1414,7 +1387,7 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
   pid_t pid;
   pid_t pid;
   const char *interp;
   const char *interp;
 
 
-  envblk = NULL; // Unused
+  (void) envblk;
 
 
   if ((pid = fork()) == -1) {
   if ((pid = fork()) == -1) {
     // Parent
     // Parent
@@ -1492,7 +1465,7 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
       n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
       n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
     }
     }
 
 
-    if (n < 0)
+    if (n <= 0)
       break;
       break;
 
 
     sent += n;
     sent += n;
@@ -1627,34 +1600,42 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
   return (int) total;
   return (int) total;
 }
 }
 
 
+// Print message to buffer. If buffer is large enough to hold the message,
+// return buffer. If buffer is to small, allocate large enough buffer on heap,
+// and return allocated buffer.
+static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
+  va_list ap_copy;
+  int len;
+
+  // Windows is not standard-compliant, and vsnprintf() returns -1 if
+  // buffer is too small. Also, older versions of msvcrt.dll do not have
+  // _vscprintf().  However, if size is 0, vsnprintf() behaves correctly.
+  // Therefore, we make two passes: on first pass, get required message length.
+  // On second pass, actually print the message.
+  va_copy(ap_copy, ap);
+  len = vsnprintf(NULL, 0, fmt, ap_copy);
+
+  if (len > (int) size &&
+      (size = len + 1) > 0 &&
+      (*buf = (char *) malloc(size)) == NULL) {
+    len = -1;  // Allocation failed, mark failure
+  } else {
+    va_copy(ap_copy, ap);
+    vsnprintf(*buf, size, fmt, ap_copy);
+  }
+
+  return len;
+}
+
 int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
 int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
   char mem[MG_BUF_LEN], *buf = mem;
   char mem[MG_BUF_LEN], *buf = mem;
   int len;
   int len;
 
 
-  // Print in a local buffer first, hoping that it is large enough to
-  // hold the whole message
-  len = vsnprintf(mem, sizeof(mem), fmt, ap);
-
-  if (len == 0) {
-    // Do nothing. mg_printf(conn, "%s", "") was called.
-  } else if (len < 0) {
-    // vsnprintf() error, give up
-    len = -1;
-    cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt);
-  } else if (len > (int) sizeof(mem) &&
-             (buf = (char *) malloc(len + 1)) != NULL) {
-    // Local buffer is not large enough, allocate big buffer on heap
-    vsnprintf(buf, len + 1, fmt, ap);
+  if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
     len = mg_write(conn, buf, (size_t) len);
     len = mg_write(conn, buf, (size_t) len);
+  }
+  if (buf != mem && buf != NULL) {
     free(buf);
     free(buf);
-  } else if (len > (int) sizeof(mem)) {
-    // Failed to allocate large enough buffer, give up
-    cry(conn, "%s(%s, ...): Can't allocate %d bytes, not printing anything",
-        __func__, fmt, len);
-    len = -1;
-  } else {
-    // Copy to the local buffer succeeded
-    len = mg_write(conn, buf, (size_t) len);
   }
   }
 
 
   return len;
   return len;
@@ -3826,7 +3807,7 @@ static void send_websocket_handshake(struct mg_connection *conn) {
 }
 }
 
 
 static void read_websocket(struct mg_connection *conn) {
 static void read_websocket(struct mg_connection *conn) {
-  unsigned char *mask, *buf = (unsigned char *) conn->buf + conn->request_len;
+  unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
   int n, len, mask_len, body_len, discard_len;
   int n, len, mask_len, body_len, discard_len;
 
 
   for (;;) {
   for (;;) {
@@ -3835,15 +3816,12 @@ static void read_websocket(struct mg_connection *conn) {
       mask_len = buf[1] & 128 ? 4 : 0;
       mask_len = buf[1] & 128 ? 4 : 0;
       if (len < 126) {
       if (len < 126) {
         conn->content_len = 2 + mask_len + len;
         conn->content_len = 2 + mask_len + len;
-        mask = buf + 2;
       } else if (len == 126 && body_len >= 4) {
       } else if (len == 126 && body_len >= 4) {
         conn->content_len = 4 + mask_len + ((((int) buf[2]) << 8) + buf[3]);
         conn->content_len = 4 + mask_len + ((((int) buf[2]) << 8) + buf[3]);
-        mask = buf + 4;
       } else if (body_len >= 10) {
       } else if (body_len >= 10) {
         conn->content_len = 10 + mask_len +
         conn->content_len = 10 + mask_len +
-          (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) |
+          (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
           htonl(* (uint32_t *) &buf[6]);
           htonl(* (uint32_t *) &buf[6]);
-        mask = buf + 10;
       }
       }
     }
     }
 
 
@@ -4100,7 +4078,7 @@ static void handle_lsp_request(struct mg_connection *conn, const char *path,
 
 
 int mg_upload(struct mg_connection *conn, const char *destination_dir) {
 int mg_upload(struct mg_connection *conn, const char *destination_dir) {
   const char *content_type_header, *boundary_start;
   const char *content_type_header, *boundary_start;
-  char buf[8192], path[PATH_MAX], fname[1024], boundary[100], *s;
+  char buf[MG_BUF_LEN], path[PATH_MAX], fname[1024], boundary[100], *s;
   FILE *fp;
   FILE *fp;
   int bl, n, i, j, headers_len, boundary_len, len = 0, num_uploaded_files = 0;
   int bl, n, i, j, headers_len, boundary_len, len = 0, num_uploaded_files = 0;
 
 
@@ -4196,7 +4174,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
       }
       }
       if (len > bl) {
       if (len > bl) {
         fwrite(buf, 1, len - bl, fp);
         fwrite(buf, 1, len - bl, fp);
-        memmove(buf, &buf[len - bl], len - bl);
+        memmove(buf, &buf[len - bl], bl);
         len = bl;
         len = bl;
       }
       }
     } while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
     } while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
@@ -4213,7 +4191,7 @@ static int is_put_or_delete_request(const struct mg_connection *conn) {
 
 
 static int get_first_ssl_listener_index(const struct mg_context *ctx) {
 static int get_first_ssl_listener_index(const struct mg_context *ctx) {
   int i, index = -1;
   int i, index = -1;
-  for (i = 0; i < ctx->num_listening_sockets; i++) {
+  for (i = 0; index == -1 && i < ctx->num_listening_sockets; i++) {
     index = ctx->listening_sockets[i].is_ssl ? i : -1;
     index = ctx->listening_sockets[i].is_ssl ? i : -1;
   }
   }
   return index;
   return index;
@@ -4531,10 +4509,10 @@ static const char *ssl_error(void) {
 
 
 static void ssl_locking_callback(int mode, int mutex_num, const char *file,
 static void ssl_locking_callback(int mode, int mutex_num, const char *file,
                                  int line) {
                                  int line) {
-  line = 0;    // Unused
-  file = NULL; // Unused
+  (void) line;
+  (void) file;
 
 
-  if (mode & CRYPTO_LOCK) {
+  if (mode & 1) {  // 1 is CRYPTO_LOCK
     (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
     (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
   } else {
   } else {
     (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
     (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
@@ -4580,7 +4558,6 @@ static int load_dll(struct mg_context *ctx, const char *dll_name,
 
 
 // Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
 // Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
 static int set_ssl_option(struct mg_context *ctx) {
 static int set_ssl_option(struct mg_context *ctx) {
-  struct mg_connection *conn;
   int i, size;
   int i, size;
   const char *pem;
   const char *pem;
 
 
@@ -4596,14 +4573,10 @@ static int set_ssl_option(struct mg_context *ctx) {
   }
   }
 #endif // NO_SSL_DL
 #endif // NO_SSL_DL
 
 
-  // Initialize SSL crap
+  // Initialize SSL library
   SSL_library_init();
   SSL_library_init();
   SSL_load_error_strings();
   SSL_load_error_strings();
 
 
-  if ((ctx->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
-    cry(fc(ctx), "SSL_CTX_new (client) error: %s", ssl_error());
-  }
-
   if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
   if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
     cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
     cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
     return 0;
     return 0;
@@ -4611,11 +4584,10 @@ static int set_ssl_option(struct mg_context *ctx) {
 
 
   // If user callback returned non-NULL, that means that user callback has
   // If user callback returned non-NULL, that means that user callback has
   // set up certificate itself. In this case, skip sertificate setting.
   // set up certificate itself. In this case, skip sertificate setting.
-  conn = fc(ctx);
-  conn->request_info.ev_data = ctx->ssl_ctx;
-  if (call_user(conn, MG_INIT_SSL) == NULL &&
-      (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0 ||
-       SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0)) {
+  fc(ctx)->request_info.ev_data = ctx->ssl_ctx;
+  if (call_user(fc(ctx), MG_INIT_SSL) == NULL &&
+      (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
+       SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
     cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
     cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
     return 0;
     return 0;
   }
   }
@@ -4682,17 +4654,17 @@ static void close_socket_gracefully(struct mg_connection *conn) {
   int n;
   int n;
 #endif
 #endif
   struct linger linger;
   struct linger linger;
-  int sock = conn->client.sock;
 
 
   // Set linger option to avoid socket hanging out after close. This prevent
   // Set linger option to avoid socket hanging out after close. This prevent
   // ephemeral port exhaust problem under high QPS.
   // ephemeral port exhaust problem under high QPS.
   linger.l_onoff = 1;
   linger.l_onoff = 1;
   linger.l_linger = 1;
   linger.l_linger = 1;
-  setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
+  setsockopt(conn->client.sock, SOL_SOCKET, SO_LINGER,
+             (char *) &linger, sizeof(linger));
 
 
   // Send FIN to the client
   // Send FIN to the client
-  (void) shutdown(sock, SHUT_WR);
-  set_non_blocking_mode(sock);
+  shutdown(conn->client.sock, SHUT_WR);
+  set_non_blocking_mode(conn->client.sock);
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
   // Read and discard pending incoming data. If we do not do that and close the
   // Read and discard pending incoming data. If we do not do that and close the
@@ -4706,23 +4678,24 @@ static void close_socket_gracefully(struct mg_connection *conn) {
 #endif
 #endif
 
 
   // Now we know that our FIN is ACK-ed, safe to close
   // Now we know that our FIN is ACK-ed, safe to close
-  (void) closesocket(sock);
+  closesocket(conn->client.sock);
 }
 }
 
 
 static void close_connection(struct mg_connection *conn) {
 static void close_connection(struct mg_connection *conn) {
   conn->must_close = 1;
   conn->must_close = 1;
-
-  if (conn->ssl) {
-    SSL_free(conn->ssl);
-    conn->ssl = NULL;
-  }
-
   if (conn->client.sock != INVALID_SOCKET) {
   if (conn->client.sock != INVALID_SOCKET) {
     close_socket_gracefully(conn);
     close_socket_gracefully(conn);
   }
   }
+  // Must be done AFTER socket is closed
+  if (conn->ssl != NULL) {
+    SSL_free(conn->ssl);
+  }
 }
 }
 
 
 void mg_close_connection(struct mg_connection *conn) {
 void mg_close_connection(struct mg_connection *conn) {
+  if (conn->client_ssl_ctx != NULL) {
+    SSL_CTX_free((SSL_CTX *) conn->client_ssl_ctx);
+  }
   close_connection(conn);
   close_connection(conn);
   free(conn);
   free(conn);
 }
 }
@@ -4733,17 +4706,12 @@ struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
   struct mg_connection *conn = NULL;
   struct mg_connection *conn = NULL;
   struct sockaddr_in sin;
   struct sockaddr_in sin;
   struct hostent *he;
   struct hostent *he;
-  SSL_CTX *ssl = NULL;
   int sock;
   int sock;
 
 
   if (host == NULL) {
   if (host == NULL) {
     snprintf(ebuf, ebuf_len, "%s", "NULL host");
     snprintf(ebuf, ebuf_len, "%s", "NULL host");
   } else if (use_ssl && SSLv23_client_method == NULL) {
   } else if (use_ssl && SSLv23_client_method == NULL) {
     snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
     snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
-#ifndef NO_SSL
-  } else if (use_ssl && (ssl = SSL_CTX_new(SSLv23_client_method())) == NULL) {
-    snprintf(ebuf, ebuf_len, "SSL_CTX_new: %s", ssl_error());
-#endif // NO_SSL
   } else if ((he = gethostbyname(host)) == NULL) {
   } else if ((he = gethostbyname(host)) == NULL) {
     snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
     snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
   } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
   } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
@@ -4760,6 +4728,14 @@ struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
                 calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
                 calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
       snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
       snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
       closesocket(sock);
       closesocket(sock);
+#ifndef NO_SSL
+    } else if (use_ssl && (conn->client_ssl_ctx =
+                           SSL_CTX_new(SSLv23_client_method())) == NULL) {
+      snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
+      closesocket(sock);
+      free(conn);
+      conn = NULL;
+#endif // NO_SSL
     } else {
     } else {
       conn->buf_size = MAX_REQUEST_SIZE;
       conn->buf_size = MAX_REQUEST_SIZE;
       conn->buf = (char *) (conn + 1);
       conn->buf = (char *) (conn + 1);
@@ -4768,13 +4744,13 @@ struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
       conn->client.rsa.sin = sin;
       conn->client.rsa.sin = sin;
       conn->client.is_ssl = use_ssl;
       conn->client.is_ssl = use_ssl;
       if (use_ssl) {
       if (use_ssl) {
-        sslize(conn, ssl, SSL_connect);
+        // SSL_CTX_set_verify call is needed to switch off server certificate
+        // checking, which is off by default in OpenSSL and on in yaSSL.
+        SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
+        sslize(conn, conn->client_ssl_ctx, SSL_connect);
       }
       }
     }
     }
   }
   }
-  if (ssl != NULL) {
-    SSL_CTX_free(ssl);
-  }
 
 
   return conn;
   return conn;
 }
 }
@@ -4827,28 +4803,8 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
   if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
   if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
   } else if (mg_vprintf(conn, fmt, ap) <= 0) {
   } else if (mg_vprintf(conn, fmt, ap) <= 0) {
     snprintf(ebuf, ebuf_len, "%s", "Error sending request");
     snprintf(ebuf, ebuf_len, "%s", "Error sending request");
-  } else if (!getreq(conn, ebuf, ebuf_len)) {
   } else {
   } else {
-#if 0
-      // Write chunk of data that may be in the user's buffer
-      data_length -= req_length;
-      if (data_length > 0 &&
-        fwrite(buf + req_length, 1, data_length, fp) != (size_t) data_length) {
-        cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
-        fclose(fp);
-        fp = NULL;
-      }
-      // Read the rest of the response and write it to the file. Do not use
-      // mg_read() cause we didn't set conn->content_len properly.
-      while (fp && (data_length = pull(0, conn, buf2, sizeof(buf2))) > 0) {
-        if (fwrite(buf2, 1, data_length, fp) != (size_t) data_length) {
-          cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
-          fclose(fp);
-          fp = NULL;
-          break;
-        }
-      }
-#endif
+    getreq(conn, ebuf, ebuf_len);
   }
   }
   if (ebuf[0] != '\0' && conn != NULL) {
   if (ebuf[0] != '\0' && conn != NULL) {
     mg_close_connection(conn);
     mg_close_connection(conn);
@@ -5116,9 +5072,6 @@ static void free_context(struct mg_context *ctx) {
   if (ctx->ssl_ctx != NULL) {
   if (ctx->ssl_ctx != NULL) {
     SSL_CTX_free(ctx->ssl_ctx);
     SSL_CTX_free(ctx->ssl_ctx);
   }
   }
-  if (ctx->client_ssl_ctx != NULL) {
-    SSL_CTX_free(ctx->client_ssl_ctx);
-  }
 #ifndef NO_SSL
 #ifndef NO_SSL
   if (ssl_mutexes != NULL) {
   if (ssl_mutexes != NULL) {
     free(ssl_mutexes);
     free(ssl_mutexes);