Browse Source

bufq: make write/pass methods more robust

- related to #11242 where curl enters busy loop when
  sending http2 data to the server

Closes #11247
Stefan Eissing 9 months ago
parent
commit
73022b52c1
1 changed files with 23 additions and 5 deletions
  1. 23 5
      lib/bufq.c

+ 23 - 5
lib/bufq.c

@@ -418,7 +418,8 @@ ssize_t Curl_bufq_write(struct bufq *q,
       break;
     }
     n = chunk_append(tail, buf, len);
-    DEBUGASSERT(n);
+    if(!n)
+      break;
     nwritten += n;
     buf += n;
     len -= n;
@@ -528,6 +529,14 @@ ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
       }
       break;
     }
+    if(!chunk_written) {
+      if(!nwritten) {
+        /* treat as blocked */
+        *err = CURLE_AGAIN;
+        nwritten = -1;
+      }
+      break;
+    }
     Curl_bufq_skip(q, (size_t)chunk_written);
     nwritten += chunk_written;
   }
@@ -551,7 +560,8 @@ ssize_t Curl_bufq_write_pass(struct bufq *q,
           /* real error, fail */
           return -1;
         }
-        /* would block */
+        /* would block, bufq is full, give up */
+        break;
       }
     }
 
@@ -562,16 +572,24 @@ ssize_t Curl_bufq_write_pass(struct bufq *q,
         /* real error, fail */
         return -1;
       }
-      /* no room in bufq, bail out */
-      goto out;
+      /* no room in bufq */
+      break;
     }
+    /* edge case of writer returning 0 (and len is >0)
+     * break or we might enter an infinite loop here */
+    if(n == 0)
+      break;
+
     /* Maybe only part of `data` has been added, continue to loop */
     buf += (size_t)n;
     len -= (size_t)n;
     nwritten += (size_t)n;
   }
 
-out:
+  if(!nwritten && len) {
+    *err = CURLE_AGAIN;
+    return -1;
+  }
   return nwritten;
 }