cURL / Mailing Lists / curl-library / Single Mail

curl-library

[RFC PATCH] Support for overriding open function for file: URLs

From: Mike Crowe <mac_at_mcrowe.com>
Date: Mon, 12 Dec 2011 17:05:06 +0000

I'd like to be able to change the actual path opened when libcurl
handles file:/// URLs. It seems that the easiest way to do this would
be to support an alternative function that is called by file_connect
when it wants to open a file. This patch does this and if the general
approach is acceptable I'll knock it into better shape. But, before
that I have a few questions:

1. CURLOPT_OPENFILEFUNCTION sounds rather more generic than it
is. CURLOPT_OPENFILEURLFUNCTION is unwieldy. I'm open to suggestions
for a new name.

2. Is it really worth adding CURLOPT_CLOSEFILEFUNCTION? I don't need
it and it's not clear that anyone else will either.

3. This patch doesn't change file_upload at all. It looks like the
easiest way to do so would be to use fdopen but it's not clear to me
what this code gains from using stdio as it is.

Thanks.

Mike.

---
 include/curl/curl.h |   22 ++++++++++++
 lib/file.c          |   89 +++++++++++++++++++++++++++++++--------------------
 lib/url.c           |   20 +++++++++++
 lib/urldata.h       |    4 ++
 4 files changed, 100 insertions(+), 35 deletions(-)
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 8f82348..0c2cc46 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -342,6 +342,15 @@ typedef curl_socket_t
 typedef int
 (*curl_closesocket_callback)(void *clientp, curl_socket_t item);
 
+typedef curl_socket_t
+(*curl_openfile_callback)(void *clientp,
+                          const char *filename,
+                          int flags,
+                          mode_t mode);
+
+typedef int
+(*curl_closefile_callback)(void *clientp, curl_socket_t item);
+
 typedef enum {
   CURLIOE_OK,            /* I/O operation successful */
   CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
@@ -1489,6 +1498,19 @@ typedef enum {
   /* Set the name servers to use for DNS resolution */
   CINIT(DNS_SERVERS, OBJECTPOINT, 211),
 
+  /* Callback function for opening file: URLs (instead of
+     open(2)). Optionally, callback is able to refuse to connect
+     returning CURL_SOCKET_BAD.  The callback should have type
+     curl_openfile_callback */
+  CINIT(OPENFILEFUNCTION, FUNCTIONPOINT, 212),
+  CINIT(OPENFILEDATA, OBJECTPOINT, 213),
+
+  /* Callback function for closing file: URLs (instead of
+     close(2)). The callback should have type
+     curl_closefile_callback */
+  CINIT(CLOSEFILEFUNCTION, FUNCTIONPOINT, 214),
+  CINIT(CLOSEFILEDATA, OBJECTPOINT, 215),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/file.c b/lib/file.c
index 4447c73..83f8c57 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -213,45 +213,56 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
     file = data->state.proto.file;
     Curl_safefree(file->freepath);
     file->path = NULL;
-    if(file->fd != -1)
-      close(file->fd);
+    if(file->fd != -1) {
+      if(data->set.fclosefile)
+        data->set.fclosefile(data->set.closefile_client, file->fd);
+      else
+        close(file->fd);
+    }
     file->fd = -1;
   }
 
-#ifdef DOS_FILESYSTEM
-  /* If the first character is a slash, and there's
-     something that looks like a drive at the beginning of
-     the path, skip the slash.  If we remove the initial
-     slash in all cases, paths without drive letters end up
-     relative to the current directory which isn't how
-     browsers work.
-
-     Some browsers accept | instead of : as the drive letter
-     separator, so we do too.
-
-     On other platforms, we need the slash to indicate an
-     absolute pathname.  On Windows, absolute paths start
-     with a drive letter.
-  */
-  actual_path = real_path;
-  if((actual_path[0] == '/') &&
-      actual_path[1] &&
-     (actual_path[2] == ':' || actual_path[2] == '|')) {
-    actual_path[2] = ':';
-    actual_path++;
+  if(data->set.fopenfile) {
+    fd = data->set.fopenfile(data->set.openfile_client,
+                             real_path, O_RDONLY, 0);
+    file->path = real_path;
   }
+  else {
+#ifdef DOS_FILESYSTEM
+    /* If the first character is a slash, and there's
+       something that looks like a drive at the beginning of
+       the path, skip the slash.  If we remove the initial
+       slash in all cases, paths without drive letters end up
+       relative to the current directory which isn't how
+       browsers work.
+
+       Some browsers accept | instead of : as the drive letter
+       separator, so we do too.
+
+       On other platforms, we need the slash to indicate an
+       absolute pathname.  On Windows, absolute paths start
+       with a drive letter.
+    */
+    actual_path = real_path;
+    if((actual_path[0] == '/') &&
+       actual_path[1] &&
+       (actual_path[2] == ':' || actual_path[2] == '|')) {
+      actual_path[2] = ':';
+      actual_path++;
+    }
 
-  /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
-  for(i=0; actual_path[i] != '\0'; ++i)
-    if(actual_path[i] == '/')
-      actual_path[i] = '\\';
+    /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
+    for(i=0; actual_path[i] != '\0'; ++i)
+      if(actual_path[i] == '/')
+        actual_path[i] = '\\';
 
-  fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
-  file->path = actual_path;
+    fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
+    file->path = actual_path;
 #else
-  fd = open_readonly(real_path, O_RDONLY);
-  file->path = real_path;
+    fd = open_readonly(real_path, O_RDONLY);
+    file->path = real_path;
 #endif
+  }
   file->freepath = real_path; /* free this when done */
 
   file->fd = fd;
@@ -275,8 +286,12 @@ static CURLcode file_done(struct connectdata *conn,
   if(file) {
     Curl_safefree(file->freepath);
     file->path = NULL;
-    if(file->fd != -1)
-      close(file->fd);
+    if(file->fd != -1) {
+      if(conn->data->set.fclosefile)
+        conn->data->set.fclosefile(conn->data->set.closefile_client, file->fd);
+      else
+        close(file->fd);
+    }
     file->fd = -1;
   }
 
@@ -292,8 +307,12 @@ static CURLcode file_disconnect(struct connectdata *conn,
   if(file) {
     Curl_safefree(file->freepath);
     file->path = NULL;
-    if(file->fd != -1)
-      close(file->fd);
+    if(file->fd != -1) {
+      if(conn->data->set.fclosefile)
+        conn->data->set.fclosefile(conn->data->set.closefile_client, file->fd);
+      else
+        close(file->fd);
+    }
     file->fd = -1;
   }
 
diff --git a/lib/url.c b/lib/url.c
index 42e1756..6092661 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2263,6 +2263,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     data->set.closesocket_client = va_arg(param, void *);
     break;
 
+  case CURLOPT_OPENFILEFUNCTION:
+    /* open file callback function: called when opening a file: URL.
+     */
+    data->set.fopenfile = va_arg(param, curl_openfile_callback);
+    break;
+
+  case CURLOPT_OPENFILEDATA:
+    /* open file callback data pointer. Might be NULL.
+     */
+    data->set.openfile_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_CLOSEFILEFUNCTION:
+    data->set.fclosefile = va_arg(param, curl_closefile_callback);
+    break;
+
+  case CURLOPT_CLOSEFILEDATA:
+    data->set.closefile_client = va_arg(param, void *);
+    break;
+
   case CURLOPT_SSL_SESSIONID_CACHE:
     data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE;
     break;
diff --git a/lib/urldata.h b/lib/urldata.h
index 53df18c..365ef4a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1393,6 +1393,10 @@ struct UserDefined {
   curl_closesocket_callback fclosesocket; /* function for closing the
                                              socket */
   void* closesocket_client;
+  curl_openfile_callback fopenfile;
+  void *openfile_client;
+  curl_closefile_callback fclosefile;
+  void *closefile_client;
 
   void *seek_client;    /* pointer to pass to the seek callback */
   /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
-- 
1.7.7.3
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2011-12-12