cURL / Mailing Lists / curl-users / Single Mail

curl-users

[PATCH] Make stdin non-blocking for curl -T-

From: Eric Wong <normalperson_at_yhbt.net>
Date: Sat, 6 Jun 2009 17:27:57 -0700

This allows curl to be used as a client-side tunnel for
arbitrary stream protocols by abusing chunked transfer encoding
in both the request and response (requires server support, of
course).

If attempting to read from stdin returns EAGAIN, then we pause
our sender. This leaves curl to attempt to read from the socket
while reading from stdin (and thus sending) is paused. A
successful read from the server that triggers a write in the
client will unpause our sender.

This change was needed to allow successfully tunneling the git
protocol over HTTP (--no-buffer is needed, as well).

A better solution would be to move to the curl_multi_* interface
allowing us to poll() stdin along with the TCP socket, but
that's probably a bigger project...

---
 src/main.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/src/main.c b/src/main.c
index d00ede8..4f473d5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -498,6 +498,7 @@ struct Configurable {
   long httpversion;
   bool progressmode;
   bool nobuffer;
+  bool readbusy; /* set when reading input returns EAGAIN */
   bool globoff;
   bool use_httpget;
   bool insecure_ok; /* set TRUE to allow insecure SSL connects */
@@ -3226,6 +3227,19 @@ static void go_sleep(long ms)
 #endif
 }
 
+/* maybe we could just use Curl_nonblock() instead ... */
+static void set_nonblocking(struct Configurable *config, int fd)
+{
+#if defined(HAVE_FCNTL_O_NONBLOCK)
+  int flags = fcntl(fd, F_GETFL, 0);
+
+  if (flags >= 0)
+    flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+  else
+    warnf(config, "fcntl failed on fd=%d: %s\n", fd, strerror(errno));
+#endif
+}
+
 static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
 {
   size_t rc;
@@ -3255,6 +3269,11 @@ static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
     out->bytes += (sz * nmemb);
   }
 
+  if(config->readbusy) {
+    config->readbusy = false;
+    curl_easy_pause(config->easy, CURLPAUSE_CONT);
+  }
+
   if(config->nobuffer)
     /* disable output buffering */
     fflush(out->stream);
@@ -3320,9 +3339,16 @@ static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
   struct InStruct *in=(struct InStruct *)userp;
 
   rc = read(in->fd, buffer, sz*nmemb);
-  if(rc < 0)
+  if(rc < 0) {
+    if(errno == EAGAIN) {
+      errno = 0;
+      in->config->readbusy = true;
+      return CURL_READFUNC_PAUSE;
+    }
     /* since size_t is unsigned we can't return negative values fine */
-    return 0;
+    rc = 0;
+  }
+  in->config->readbusy = false;
   return (size_t)rc;
 }
 
@@ -4491,6 +4517,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
         else if(uploadfile && curlx_strequal(uploadfile, "-")) {
           SET_BINMODE(stdin);
           infd = STDIN_FILENO;
+          set_nonblocking(config, infd);
         }
 
         if(uploadfile && config->resume_from_current)
-- 
Eric Wong
-------------------------------------------------------------------
List admin: http://cool.haxx.se/cgi-bin/mailman/listinfo/curl-users
FAQ:        http://curl.haxx.se/docs/faq.html
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2001-09-17