cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH] CURL : ADD WRITE SUPPORT NOT WORKING

From: Richard W.M. Jones <rjones_at_redhat.com>
Date: Sat, 21 Jun 2014 22:10:18 +0100

---
 plugins/curl/curl.c                 | 75 +++++++++++++++++++++++++++++++++++--
 plugins/curl/nbdkit-curl-plugin.pod | 10 +++--
 2 files changed, 78 insertions(+), 7 deletions(-)
diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
index f922832..7b99c06 100644
--- a/plugins/curl/curl.c
+++ b/plugins/curl/curl.c
@@ -31,6 +31,14 @@
  * SUCH DAMAGE.
  */
 
+/* NB: The terminology used by libcurl is confusing!
+ *
+ * WRITEFUNCTION / write_cb is used when reading from the remote server
+ * READFUNCTION / read_cb is used when writing to the remote server.
+ *
+ * We use the same terminology as libcurl here.
+ */
+
 #include <config.h>
 
 #include <stdio.h>
@@ -145,6 +153,8 @@ struct curl_handle {
   char errbuf[CURL_ERROR_SIZE];
   char *write_buf;
   uint32_t write_count;
+  const char *read_buf;
+  uint32_t read_count;
 };
 
 /* Translate CURLcode to nbdkit_error. */
@@ -156,6 +166,7 @@ struct curl_handle {
 
 static size_t header_cb (void *ptr, size_t size, size_t nmemb, void *opaque);
 static size_t write_cb (char *ptr, size_t size, size_t nmemb, void *opaque);
+static size_t read_cb (void *ptr, size_t size, size_t nmemb, void *opaque);
 
 /* Create the per-connection handle. */
 static void *
@@ -241,12 +252,15 @@ CURLOPT_PROXY
     nbdkit_debug ("accept range supported (for HTTP/HTTPS)");
   }
 
-  /* Get set up for reading. */
+  /* Get set up for reading and writing. */
   curl_easy_setopt (h->c, CURLOPT_HEADERFUNCTION, NULL);
   curl_easy_setopt (h->c, CURLOPT_HEADERDATA, NULL);
-  curl_easy_setopt (h->c, CURLOPT_NOBODY, 0); /* No Body, not nobody! */
   curl_easy_setopt (h->c, CURLOPT_WRITEFUNCTION, write_cb);
   curl_easy_setopt (h->c, CURLOPT_WRITEDATA, h);
+  if (!readonly) {
+    curl_easy_setopt (h->c, CURLOPT_READFUNCTION, read_cb);
+    curl_easy_setopt (h->c, CURLOPT_READDATA, h);
+  }
 
   nbdkit_debug ("returning new handle %p", h);
 
@@ -307,7 +321,7 @@ curl_get_size (void *handle)
   return h->exportsize;
 }
 
-/* Read data from the file. */
+/* Read data from the remote server. */
 static int
 curl_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
 {
@@ -321,6 +335,9 @@ curl_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
   h->write_buf = buf;
   h->write_count = count;
 
+  curl_easy_setopt (h->c, CURLOPT_NOBODY, 0); /* No Body, not nobody! */
+  curl_easy_setopt (h->c, CURLOPT_HTTPGET, 1);
+
   /* Make an HTTP range request. */
   snprintf (range, sizeof range, "%" PRIu64 "-%" PRIu64,
             offset, offset + count);
@@ -361,6 +378,57 @@ write_cb (char *ptr, size_t size, size_t nmemb, void *opaque)
   return orig_realsize;
 }
 
+/* Write data to the remote server. */
+static int
+curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
+{
+  struct curl_handle *h = handle;
+  CURLcode r;
+  char range[128];
+
+  /* Tell the read_cb where we want the data to be read from.  read_cb
+   * will update this if the data comes in multiple sections.
+   */
+  h->read_buf = buf;
+  h->read_count = count;
+
+  curl_easy_setopt (h->c, CURLOPT_UPLOAD, 1);
+
+  /* Make an HTTP range request. */
+  snprintf (range, sizeof range, "%" PRIu64 "-%" PRIu64,
+            offset, offset + count);
+  curl_easy_setopt (h->c, CURLOPT_RANGE, range);
+
+  /* The assumption here is that curl will look after timeouts. */
+  while (h->read_count > 0) {
+    r = curl_easy_perform (h->c);
+    if (r != CURLE_OK) {
+      display_curl_error (h, r, "pwrite: curl_easy_perform");
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static size_t
+read_cb (void *ptr, size_t size, size_t nmemb, void *opaque)
+{
+  struct curl_handle *h = opaque;
+  size_t realsize = size * nmemb;
+
+  assert (h->read_buf);
+  if (realsize > h->read_count)
+    return CURL_READFUNC_ABORT;
+
+  memcpy (ptr, h->read_buf, realsize);
+
+  h->read_count -= realsize;
+  h->read_buf += realsize;
+
+  return realsize;
+}
+
 static struct nbdkit_plugin plugin = {
   .name              = "curl",
   .version           = PACKAGE_VERSION,
@@ -373,6 +441,7 @@ static struct nbdkit_plugin plugin = {
   .close             = curl_close,
   .get_size          = curl_get_size,
   .pread             = curl_pread,
+  .pwrite            = curl_pwrite,
 };
 
 NBDKIT_REGISTER_PLUGIN(plugin)
diff --git a/plugins/curl/nbdkit-curl-plugin.pod b/plugins/curl/nbdkit-curl-plugin.pod
index 79659a5..97b6e7d 100644
--- a/plugins/curl/nbdkit-curl-plugin.pod
+++ b/plugins/curl/nbdkit-curl-plugin.pod
@@ -8,7 +8,7 @@ nbdkit-curl-plugin - nbdkit curl plugin (HTTP, FTP, SSH and other protocols)
 
  nbdkit -r curl url=http://example.com/disk.img
 
- nbdkit -r curl url=sftp://you@example.com/~/disk.img
+ nbdkit curl url=sftp://you@example.com/~/disk.img
 
 =head1 DESCRIPTION
 
@@ -20,7 +20,9 @@ how it was compiled, but most versions will handle HTTP, HTTPS, FTP,
 FTPS and SFTP (see: S<C<curl -V>>).  For more information about
 libcurl, see L<http://curl.haxx.se>.
 
-This plugin can B<only> handle B<readonly> connections.
+B<Note:> This plugin supports writable connections.  However for HTTP,
+you may not want nbdkit to issue POST requests to the remote server.
+To force nbdkit to use a readonly connection, pass the I<-r> flag.
 
 =head2 EXAMPLES
 
@@ -34,12 +36,12 @@ control ports and protocols used to serve NBD see L<nbdkit(1)>).
 You can also access SSH servers.  This uses the SFTP protocol which is
 built into most SSH servers:
 
- nbdkit -r curl url=sftp://example.com/~/disk.img
+ nbdkit curl url=sftp://example.com/~/disk.img
 
 You may need to specify a username and/or a password.  In this example
 the password is read from stdin:
 
- nbdkit -r curl url=sftp://example.com/~/disk.img username=fred password=-
+ nbdkit curl url=sftp://example.com/~/disk.img username=fred password=-
 
 =head1 PARAMETERS
 
-- 
1.9.0
--NzB8fVQJ5HfG6fxh
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLQpMaXN0IGFkbWluOiBodHRwOi8vY29vbC5oYXh4LnNlL2xpc3QvbGlzdGluZm8v
Y3VybC1saWJyYXJ5CkV0aXF1ZXR0ZTogIGh0dHA6Ly9jdXJsLmhheHguc2UvbWFpbC9ldGlxdWV0
dGUuaHRtbA==
--NzB8fVQJ5HfG6fxh--
Received on 2001-09-17