]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
rustls: read of zero bytes might be okay
authorJacob Hoffman-Andrews <github@hoffman-andrews.com>
Sat, 13 Nov 2021 03:33:19 +0000 (19:33 -0800)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 13 Nov 2021 21:57:51 +0000 (22:57 +0100)
When we're reading out plaintext from rustls' internal buffers, we might
get a read of zero bytes (meaning a clean TCP close, including
close_notify). However, we shouldn't return immediately when that
happens, since we may have already copied out some plaintext bytes.
Break out of the loop when we get a read of zero bytes, and figure out
which path we're dealing with.

Acked-by: Kevin Burke
Closes #8003

lib/vtls/rustls.c

index 76519b2aefcdc723ac0bd067ab52d65fac9dd361..da1c252dc9afe06081c58e2dbe6e53c3bfe6dc87 100644 (file)
@@ -157,7 +157,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
       plainlen - plain_bytes_copied,
       &n);
     if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
-      infof(data, "cr_recv got 0 bytes of plaintext");
+      infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later.");
       backend->data_pending = FALSE;
       break;
     }
@@ -168,8 +168,10 @@ cr_recv(struct Curl_easy *data, int sockindex,
       return -1;
     }
     else if(n == 0) {
-      *err = CURLE_OK;
-      return 0;
+      /* n == 0 indicates clean EOF, but we may have read some other
+         plaintext bytes before we reached this. Break out of the loop
+         so we can figure out whether to return success or EOF. */
+      break;
     }
     else {
       infof(data, "cr_recv copied out %ld bytes of plaintext", n);
@@ -177,15 +179,23 @@ cr_recv(struct Curl_easy *data, int sockindex,
     }
   }
 
-  /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet
-     read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this
-     as EOF. */
-  if(plain_bytes_copied == 0) {
+  if(plain_bytes_copied) {
+    *err = CURLE_OK;
+    return plain_bytes_copied;
+  }
+
+  /* If we wrote out 0 plaintext bytes, that means either we hit a clean EOF,
+     OR we got a RUSTLS_RESULT_PLAINTEXT_EMPTY.
+     If the latter, return CURLE_AGAIN so curl doesn't treat this as EOF. */
+  if(!backend->data_pending) {
     *err = CURLE_AGAIN;
     return -1;
   }
 
-  return plain_bytes_copied;
+  /* Zero bytes read, and no RUSTLS_RESULT_PLAINTEXT_EMPTY, means the TCP
+     connection was cleanly closed (with a close_notify alert). */
+  *err = CURLE_OK;
+  return 0;
 }
 
 /*