[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH 2/3] curl: Change the API to use an abstract data type.



Change the Curl module to use an ADT to store the name of the curl
binary and the arguments.

Also add Curl.safe_args, a list of arguments that control redirects etc.

The callers in virt-v2v are changed accordingly.

There is also a (currently unused) args_of_proxy function allowing
proxy parameters to be set.
---
 mllib/curl.ml        | 48 ++++++++++++++++++++++++++++++-----------
 mllib/curl.mli       | 60 ++++++++++++++++++++++++++++++++++++++++++++--------
 v2v/copy_to_local.ml | 14 ++++++------
 v2v/vCenter.ml       | 16 ++++++++------
 4 files changed, 104 insertions(+), 34 deletions(-)

diff --git a/mllib/curl.ml b/mllib/curl.ml
index f0af160..a684fdb 100644
--- a/mllib/curl.ml
+++ b/mllib/curl.ml
@@ -20,10 +20,19 @@ open Printf
 
 open Common_utils
 
-type curl_args = (string * string option) list
+let quote = Filename.quote
 
-let run curl_args =
-  let config_file, chan = Filename.open_temp_file "v2vcurl" ".conf" in
+type t = {
+  curl : string;
+  args : args;
+}
+and args = (string * string option) list
+
+let create ?(curl = "curl") args =
+  { curl = curl; args = args }
+
+let run { curl = curl; args = args } =
+  let config_file, chan = Filename.open_temp_file "curl" ".conf" in
   List.iter (
     function
     | name, None -> fprintf chan "%s\n" name
@@ -44,21 +53,36 @@ let run curl_args =
         | c -> output_char chan c
       done;
       fprintf chan "\"\n"
-  ) curl_args;
+  ) args;
   close_out chan;
 
-  let cmd = sprintf "curl -q --config %s" (Filename.quote config_file) in
+  let cmd = sprintf "%s -q --config %s" (quote curl) (quote config_file) in
   let lines = external_command ~echo_cmd:false cmd in
   Unix.unlink config_file;
   lines
 
-let print_curl_command chan curl_args =
-  fprintf chan "curl -q";
+let to_string { curl = curl; args = args } =
+  let b = Buffer.create 128 in
+  bprintf b "%s -q" (quote curl);
   List.iter (
     function
-    | name, None -> fprintf chan " --%s" name
+    | name, None -> bprintf b " --%s" name
     (* Don't print passwords in the debug output. *)
-    | "user", Some _ -> fprintf chan " --user <hidden>"
-    | name, Some value -> fprintf chan " --%s %s" name (Filename.quote value)
-  ) curl_args;
-  fprintf chan "\n";
+    | "user", Some _ -> bprintf b " --user <hidden>"
+    | name, Some value -> bprintf b " --%s %s" name (quote value)
+  ) args;
+  bprintf b "\n";
+  Buffer.contents b
+
+let print chan t = output_string chan (to_string t)
+
+type proxy = UnsetProxy | ForcedProxy of string
+
+let args_of_proxy = function
+  | UnsetProxy ->      [ "proxy", Some "" ; "noproxy", Some "*" ]
+  | ForcedProxy url -> [ "proxy", Some url; "noproxy", Some "" ]
+
+let safe_args = [
+  "max-redirs", Some "5";
+  "globoff", None;         (* Don't glob URLs. *)
+]
diff --git a/mllib/curl.mli b/mllib/curl.mli
index cd01497..31927e5 100644
--- a/mllib/curl.mli
+++ b/mllib/curl.mli
@@ -18,21 +18,63 @@
 
 (** Functions for dealing with [curl]. *)
 
-type curl_args = (string * string option) list
+type t
 
-val run : curl_args -> string list
-(** [run curl_args] runs the [curl] command.
+type args = (string * string option) list
 
-    It actually uses the [curl --config] option to pass the arguments
-    securely to curl through an external file.  Thus passwords etc are
-    not exposed to other users on the same machine.
+val create : ?curl:string -> args -> t
+(** Create a curl command handle.
 
     The curl arguments are a list of key, value pairs corresponding
     to curl command line parameters, without leading dashes,
     eg. [("user", Some "user:password")].
 
+    The optional [?curl] parameter controls the name of the curl
+    binary (default ["curl"]). *)
+
+val run : t -> string list
+(** [run t] runs previously constructed the curl command.
+
+    It actually uses the [curl --config] option to pass the arguments
+    securely to curl through an external file.  Thus passwords etc are
+    not exposed to other users on the same machine.
+
     The result is the output of curl as a list of lines. *)
 
-val print_curl_command : out_channel -> curl_args -> unit
-(** Print the curl command line.  This elides any arguments that
-    might contain passwords, so is useful for debugging. *)
+val to_string : t -> string
+(** Convert the curl command line to a string.
+
+    This elides any arguments that might contain passwords, so is
+    useful for debugging. *)
+
+val print : out_channel -> t -> unit
+(** Print the curl command line.
+
+    This elides any arguments that might contain passwords, so is
+    useful for debugging. *)
+
+type proxy =
+  | UnsetProxy            (** The proxy is forced off. *)
+  | ForcedProxy of string (** The proxy is forced to the specified URL. *)
+
+val args_of_proxy : proxy -> args
+(** Convert the proxy setting to the equivalent list of curl arguments.
+
+    To use the system proxy, no additional arguments are required, so
+    if you don't want to control the proxy (but just use the defaults)
+    you do not need to call this function at all.
+
+    Callers should append these arguments to the list of arguments
+    passed to {!create}. *)
+
+val safe_args : args
+(** This returns a list of safe arguments which can (and probably should)
+    be added to any list of arguments passed to {!create}.
+
+    Currently this list includes:
+
+    - Only follow 3XX redirects up to 5 times.
+    - Disable URL globbing.
+
+    Note this does {b not} enable redirects.  If you want to follow
+    redirects you have to add the ["location"] parameter. *)
diff --git a/v2v/copy_to_local.ml b/v2v/copy_to_local.ml
index 717ba50..d791293 100644
--- a/v2v/copy_to_local.ml
+++ b/v2v/copy_to_local.ml
@@ -198,10 +198,11 @@ read the man page virt-v2v-copy-to-local(1).
          error (f_"ssh copy command failed, see earlier errors");
 
     | ESXi _ ->
-       let curl_args = [
-         "url", Some remote_disk;
-         "output", Some local_disk;
-       ] in
+       let curl_args =
+         Curl.safe_args @ [
+           "url", Some remote_disk;
+           "output", Some local_disk;
+         ] in
        let curl_args =
          if sslverify then curl_args
          else ("insecure", None) :: curl_args in
@@ -213,9 +214,10 @@ read the man page virt-v2v-copy-to-local(1).
          if quiet () then ("silent", None) :: curl_args
          else curl_args in
 
+       let curl_h = Curl.create curl_args in
        if verbose () then
-         Curl.print_curl_command stderr curl_args;
-       ignore (Curl.run curl_args)
+         Curl.print stderr curl_h;
+       ignore (Curl.run curl_h)
 
     | Test ->
        let cmd = [ "cp"; remote_disk; local_disk ] in
diff --git a/v2v/vCenter.ml b/v2v/vCenter.ml
index d41f223..dbfdf1a 100644
--- a/v2v/vCenter.ml
+++ b/v2v/vCenter.ml
@@ -45,11 +45,12 @@ let get_session_cookie password scheme uri sslverify url =
   if !session_cookie <> "" then
     Some !session_cookie
   else (
-    let curl_args = [
-      "head", None;
-      "silent", None;
-      "url", Some url;
-    ] in
+    let curl_args =
+      Curl.safe_args @ [
+        "head", None;
+        "silent", None;
+        "url", Some url;
+      ] in
     let curl_args =
       match uri.uri_user, password with
       | None, None -> curl_args
@@ -63,10 +64,11 @@ let get_session_cookie password scheme uri sslverify url =
     let curl_args =
       if not sslverify then ("insecure", None) :: curl_args else curl_args in
 
-    let lines = Curl.run curl_args in
+    let curl_h = Curl.create curl_args in
+    let lines = Curl.run curl_h in
 
     let dump_response chan =
-      Curl.print_curl_command chan curl_args;
+      Curl.print chan curl_h;
 
       (* Dump out the output of the command. *)
       List.iter (fun x -> fprintf chan "%s\n" x) lines;
-- 
2.7.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]