GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
url-transfer.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2006-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <fstream>
31 #include <iomanip>
32 #include <iostream>
33 
34 #include "dir-ops.h"
35 #include "file-ops.h"
36 #include "file-stat.h"
37 #include "lo-sysdep.h"
38 #include "oct-env.h"
39 #include "unwind-prot.h"
40 #include "url-transfer.h"
41 #include "version.h"
42 
43 #if defined (HAVE_CURL)
44 # include <curl/curl.h>
45 # include <curl/curlver.h>
46 # include <curl/easy.h>
47 #endif
48 
49 namespace octave
50 {
52  : m_host_or_url (), m_valid (false), m_ftp (false),
53  m_ascii_mode (false), m_ok (true), m_errmsg (),
54  m_curr_istream (&std::cin), m_curr_ostream (&std::cout)
55  { }
56 
57  base_url_transfer::base_url_transfer (const std::string& host,
58  const std::string& /* user_arg */,
59  const std::string& /* passwd */,
60  std::ostream& os)
61  : m_host_or_url (host), m_valid (false), m_ftp (true),
62  m_ascii_mode (false), m_ok (true), m_errmsg (),
63  m_curr_istream (&std::cin), m_curr_ostream (&os)
64  { }
65 
66  base_url_transfer::base_url_transfer (const std::string& url,
67  std::ostream& os)
68  : m_host_or_url (url), m_valid (false), m_ftp (false),
69  m_ascii_mode (false), m_ok (true), m_errmsg (),
70  m_curr_istream (&std::cin), m_curr_ostream (&os)
71  { }
72 
73  void
74  base_url_transfer::delete_file (const std::string& file)
75  {
76  sys::unlink (file);
77  }
78 
79  void
80  base_url_transfer::mget_directory (const std::string& directory,
81  const std::string& target)
82  {
83  std::string sep = sys::file_ops::dir_sep_str ();
84  sys::file_stat fs (directory);
85 
86  if (! fs || ! fs.is_dir ())
87  {
88  std::string msg;
89  int status = sys::mkdir (directory, 0777, msg);
90 
91  if (status < 0)
92  {
93  m_ok = false;
94  m_errmsg = "__ftp_mget__: can not create directory '"
95  + target + sep + directory + "': " + msg;
96  return;
97  }
98  }
99 
100  cwd (directory);
101 
102  if (good ())
103  {
104  unwind_protect_safe frame;
105 
106  frame.add_fcn (reset_path, this);
107 
108  string_vector sv = list ();
109 
110  for (octave_idx_type i = 0; i < sv.numel (); i++)
111  {
112  time_t ftime;
113  bool fisdir;
114  double fsize;
115 
116  get_fileinfo (sv(i), fsize, ftime, fisdir);
117 
118  if (fisdir)
119  mget_directory (sv(i), target + directory + sep);
120  else
121  {
122  std::string realfile = target + directory + sep + sv(i);
123 
124  std::ofstream ofile =
125  sys::ofstream (realfile.c_str (),
126  std::ios::out | std::ios::binary);
127 
128  if (! ofile.is_open ())
129  {
130  m_ok = false;
131  m_errmsg = "__ftp_mget__: unable to open file";
132  break;
133  }
134 
135  unwind_protect_safe frame2;
136 
137  frame2.add_fcn (delete_file, realfile);
138 
139  get (sv(i), ofile);
140 
141  ofile.close ();
142 
143  if (good ())
144  frame2.discard ();
145  }
146 
147  if (! good ())
148  break;
149  }
150  }
151  }
152 
154  base_url_transfer::mput_directory (const std::string& base,
155  const std::string& directory)
156  {
157  string_vector file_list;
158 
159  std::string realdir
160  = (base.empty ()
161  ? directory : base + sys::file_ops::dir_sep_str () + directory);
162 
163  mkdir (directory);
164 
165  if (! good ())
166  return file_list;
167 
168  cwd (directory);
169 
170  if (good ())
171  {
172  unwind_protect_safe frame;
173 
174  frame.add_fcn (reset_path, this);
175 
176  string_vector files;
177  std::string msg;
178 
179  if (sys::get_dirlist (realdir, files, msg))
180  for (octave_idx_type i = 0; i < files.numel (); i++)
181  {
182  std::string file = files (i);
183 
184  if (file == "." || file == "..")
185  continue;
186 
187  std::string realfile
188  = realdir + sys::file_ops::dir_sep_str () + file;
189 
190  sys::file_stat fs (realfile);
191 
192  if (! fs.exists ())
193  {
194  m_ok = false;
195  m_errmsg = "__ftp__mput: file '" + realfile
196  + "' does not exist";
197  break;
198  }
199 
200  if (fs.is_dir ())
201  {
202  file_list.append (mput_directory (realdir, file));
203 
204  if (! good ())
205  break;
206  }
207  else
208  {
209  // FIXME: Does ascii mode need to be flagged here?
210  std::ifstream ifile =
211  sys::ifstream (realfile.c_str (),
212  std::ios::in | std::ios::binary);
213 
214  if (! ifile.is_open ())
215  {
216  m_ok = false;
217  m_errmsg = "__ftp_mput__: unable to open file '"
218  + realfile + "'";
219  break;
220  }
221 
222  put (file, ifile);
223 
224  ifile.close ();
225 
226  if (! good ())
227  break;
228 
229  file_list.append (realfile);
230  }
231  }
232  else
233  {
234  m_ok = false;
235  m_errmsg = "__ftp_mput__: can not read the directory '"
236  + realdir + "'";
237  }
238  }
239 
240  return file_list;
241  }
242 
243 #if defined (HAVE_CURL)
244 
245  static int
246  write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
247  {
248  std::ostream& stream = *(static_cast<std::ostream *> (streamp));
249  stream.write (static_cast<const char *> (buffer), size*nmemb);
250  return (stream.fail () ? 0 : size * nmemb);
251  }
252 
253  static int
254  read_data (void *buffer, size_t size, size_t nmemb, void *streamp)
255  {
256  std::istream& stream = *(static_cast<std::istream *> (streamp));
257  stream.read (static_cast<char *> (buffer), size*nmemb);
258  if (stream.eof ())
259  return stream.gcount ();
260  else
261  return (stream.fail () ? 0 : size * nmemb);
262  }
263 
264  static size_t
265  throw_away (void *, size_t size, size_t nmemb, void *)
266  {
267  return static_cast<size_t> (size * nmemb);
268  }
269 
270  // I'd love to rewrite this as a private method of the url_transfer
271  // class, but you can't pass the va_list from the wrapper SETOPT to
272  // the curl_easy_setopt function.
273 #define SETOPT(option, parameter) \
274  do \
275  { \
276  CURLcode res = curl_easy_setopt (m_curl, option, parameter); \
277  if (res != CURLE_OK) \
278  { \
279  m_ok = false; \
280  m_errmsg = curl_easy_strerror (res); \
281  return; \
282  } \
283  } \
284  while (0)
285 
286  // Same as above but with a return value.
287 #define SETOPTR(option, parameter) \
288  do \
289  { \
290  CURLcode res = curl_easy_setopt (m_curl, option, parameter); \
291  if (res != CURLE_OK) \
292  { \
293  m_ok = false; \
294  m_errmsg = curl_easy_strerror (res); \
295  return retval; \
296  } \
297  } \
298  while (0)
299 
301  {
302  public:
303 
305  : base_url_transfer (), m_curl (curl_easy_init ()), m_errnum (), m_url (),
306  m_userpwd ()
307  {
308  if (m_curl)
309  m_valid = true;
310  else
311  m_errmsg = "can not create curl object";
312  }
313 
314  curl_transfer (const std::string& host, const std::string& user_arg,
315  const std::string& passwd, std::ostream& os)
316  : base_url_transfer (host, user_arg, passwd, os),
317  m_curl (curl_easy_init ()), m_errnum (), m_url (), m_userpwd ()
318  {
319  if (m_curl)
320  m_valid = true;
321  else
322  {
323  m_errmsg = "can not create curl object";
324  return;
325  }
326 
327  init (user_arg, passwd, std::cin, os);
328 
329  m_url = "ftp://" + host;
330  SETOPT (CURLOPT_URL, m_url.c_str ());
331 
332  // Set up the link, with no transfer.
333  perform ();
334  }
335 
336  curl_transfer (const std::string& url_str, std::ostream& os)
337  : base_url_transfer (url_str, os), m_curl (curl_easy_init ()),
338  m_errnum (), m_url (), m_userpwd ()
339  {
340  if (m_curl)
341  m_valid = true;
342  else
343  {
344  m_errmsg = "can not create curl object";
345  return;
346  }
347 
348  init ("", "", std::cin, os);
349 
350  std::string cainfo = sys::env::getenv ("CURLOPT_CAINFO");
351  if (! cainfo.empty ())
352  SETOPT (CURLOPT_CAINFO, cainfo.c_str ());
353 
354  std::string capath = sys::env::getenv ("CURLOPT_CAPATH");
355  if (! capath.empty ())
356  SETOPT (CURLOPT_CAPATH, capath.c_str ());
357 
358  SETOPT (CURLOPT_NOBODY, 0);
359 
360  // Restore the default HTTP request method to GET after setting
361  // NOBODY to true (in the init method) and back to false (above).
362  // This is needed for backward compatibility with versions of
363  // libcurl < 7.18.2.
364  SETOPT (CURLOPT_HTTPGET, 1);
365  }
366 
367  // No copying!
368 
369  curl_transfer (const curl_transfer&) = delete;
370 
372 
374  {
375  if (m_curl)
376  curl_easy_cleanup (m_curl);
377  }
378 
379  void perform (void)
380  {
382 
383  m_errnum = curl_easy_perform (m_curl);
384 
385  if (m_errnum != CURLE_OK)
386  {
387  m_ok = false;
388  m_errmsg = curl_easy_strerror (m_errnum);
389  }
390 
392  }
393 
394  std::string lasterror (void) const
395  {
396  return std::string (curl_easy_strerror (m_errnum));
397  }
398 
399  std::ostream& set_ostream (std::ostream& os)
400  {
401  std::ostream& retval = *m_curr_ostream;
402  m_curr_ostream = &os;
403  SETOPTR (CURLOPT_WRITEDATA, static_cast<void *> (m_curr_ostream));
404  return retval;
405  }
406 
407  std::istream& set_istream (std::istream& is)
408  {
409  std::istream& retval = *m_curr_istream;
410  m_curr_istream = &is;
411  SETOPTR (CURLOPT_READDATA, static_cast<void *> (m_curr_istream));
412  return retval;
413  }
414 
415  void ascii (void)
416  {
417  m_ascii_mode = true;
418  SETOPT (CURLOPT_TRANSFERTEXT, 1);
419  }
420 
421  void binary (void)
422  {
423  m_ascii_mode = false;
424  SETOPT (CURLOPT_TRANSFERTEXT, 0);
425  }
426 
427  void cwd (const std::string& path)
428  {
429  ftp_file_or_dir_action (path, "cwd");
430  }
431 
432  void del (const std::string& file)
433  {
434  ftp_file_or_dir_action (file, "dele");
435  }
436 
437  void rmdir (const std::string& path)
438  {
439  ftp_file_or_dir_action (path, "rmd");
440  }
441 
442  void mkdir (const std::string& path)
443  {
444  ftp_file_or_dir_action (path, "mkd");
445  }
446 
447  void rename (const std::string& oldname, const std::string& newname)
448  {
449  struct curl_slist *slist = nullptr;
450 
451  unwind_protect frame;
452  frame.add_fcn (curl_slist_free_all, slist);
453 
454  std::string cmd = "rnfr " + oldname;
455  slist = curl_slist_append (slist, cmd.c_str ());
456  cmd = "rnto " + newname;
457  slist = curl_slist_append (slist, cmd.c_str ());
458  SETOPT (CURLOPT_POSTQUOTE, slist);
459 
460  perform ();
461  if (! good ())
462  return;
463 
464  SETOPT (CURLOPT_POSTQUOTE, 0);
465  }
466 
467  void put (const std::string& file, std::istream& is)
468  {
469  m_url = "ftp://" + m_host_or_url + '/' + file;
470  SETOPT (CURLOPT_URL, m_url.c_str ());
471  SETOPT (CURLOPT_UPLOAD, 1);
472  SETOPT (CURLOPT_NOBODY, 0);
473  std::istream& old_is = set_istream (is);
474 
475  perform ();
476  if (! good ())
477  return;
478 
479  set_istream (old_is);
480  SETOPT (CURLOPT_NOBODY, 1);
481  SETOPT (CURLOPT_UPLOAD, 0);
482  m_url = "ftp://" + m_host_or_url;
483  SETOPT (CURLOPT_URL, m_url.c_str ());
484  }
485 
486  void get (const std::string& file, std::ostream& os)
487  {
488  m_url = "ftp://" + m_host_or_url + '/' + file;
489  SETOPT (CURLOPT_URL, m_url.c_str ());
490  SETOPT (CURLOPT_NOBODY, 0);
491  std::ostream& old_os = set_ostream (os);
492 
493  perform ();
494  if (! good ())
495  return;
496 
497  set_ostream (old_os);
498  SETOPT (CURLOPT_NOBODY, 1);
499  m_url = "ftp://" + m_host_or_url;
500  SETOPT (CURLOPT_URL, m_url.c_str ());
501  }
502 
503  void dir (void)
504  {
505  m_url = "ftp://" + m_host_or_url + '/';
506  SETOPT (CURLOPT_URL, m_url.c_str ());
507  SETOPT (CURLOPT_NOBODY, 0);
508 
509  perform ();
510  if (! good ())
511  return;
512 
513  SETOPT (CURLOPT_NOBODY, 1);
514  m_url = "ftp://" + m_host_or_url;
515  SETOPT (CURLOPT_URL, m_url.c_str ());
516  }
517 
519  {
521 
522  std::ostringstream buf;
523  m_url = "ftp://" + m_host_or_url + '/';
524  SETOPTR (CURLOPT_WRITEDATA, static_cast<void *> (&buf));
525  SETOPTR (CURLOPT_URL, m_url.c_str ());
526  SETOPTR (CURLOPT_DIRLISTONLY, 1);
527  SETOPTR (CURLOPT_NOBODY, 0);
528 
529  perform ();
530  if (! good ())
531  return retval;
532 
533  SETOPTR (CURLOPT_NOBODY, 1);
534  m_url = "ftp://" + m_host_or_url;
535  SETOPTR (CURLOPT_WRITEDATA, static_cast<void *> (m_curr_ostream));
536  SETOPTR (CURLOPT_DIRLISTONLY, 0);
537  SETOPTR (CURLOPT_URL, m_url.c_str ());
538 
539  // Count number of directory entries
540  std::string str = buf.str ();
541  octave_idx_type n = 0;
542  size_t pos = 0;
543  while (true)
544  {
545  pos = str.find_first_of ('\n', pos);
546  if (pos == std::string::npos)
547  break;
548  pos++;
549  n++;
550  }
551  retval.resize (n);
552  pos = 0;
553  for (octave_idx_type i = 0; i < n; i++)
554  {
555  size_t newpos = str.find_first_of ('\n', pos);
556  if (newpos == std::string::npos)
557  break;
558 
559  retval(i) = str.substr(pos, newpos - pos);
560  pos = newpos + 1;
561  }
562 
563  return retval;
564  }
565 
566  void get_fileinfo (const std::string& filename, double& filesize,
567  time_t& filetime, bool& fileisdir)
568  {
569  std::string path = pwd ();
570 
571  m_url = "ftp://" + m_host_or_url + '/' + path + '/' + filename;
572  SETOPT (CURLOPT_URL, m_url.c_str ());
573  SETOPT (CURLOPT_FILETIME, 1);
574  SETOPT (CURLOPT_HEADERFUNCTION, throw_away);
575  SETOPT (CURLOPT_WRITEFUNCTION, throw_away);
576 
577  // FIXME
578  // The MDTM command fails for a directory on the servers I tested
579  // so this is a means of testing for directories. It also means
580  // I can't get the date of directories!
581 
582  perform ();
583  if (! good ())
584  {
585  fileisdir = true;
586  filetime = -1;
587  filesize = 0;
588 
589  return;
590  }
591 
592  fileisdir = false;
593  time_t ft;
594  curl_easy_getinfo (m_curl, CURLINFO_FILETIME, &ft);
595  filetime = ft;
596  double fs;
597  curl_easy_getinfo (m_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fs);
598  filesize = fs;
599 
600  SETOPT (CURLOPT_WRITEFUNCTION, write_data);
601  SETOPT (CURLOPT_HEADERFUNCTION, 0);
602  SETOPT (CURLOPT_FILETIME, 0);
603  m_url = "ftp://" + m_host_or_url;
604  SETOPT (CURLOPT_URL, m_url.c_str ());
605 
606  // The MDTM command seems to reset the path to the root with the
607  // servers I tested with, so cd again into the correct path. Make
608  // the path absolute so that this will work even with servers that
609  // don't end up in the root after an MDTM command.
610  cwd ('/' + path);
611  }
612 
613  std::string pwd (void)
614  {
615  std::string retval;
616 
617  struct curl_slist *slist = nullptr;
618 
619  unwind_protect frame;
620  frame.add_fcn (curl_slist_free_all, slist);
621 
622  slist = curl_slist_append (slist, "pwd");
623  SETOPTR (CURLOPT_POSTQUOTE, slist);
624  SETOPTR (CURLOPT_HEADERFUNCTION, write_data);
625 
626  std::ostringstream buf;
627  SETOPTR (CURLOPT_WRITEHEADER, static_cast<void *>(&buf));
628 
629  perform ();
630  if (! good ())
631  return retval;
632 
633  retval = buf.str ();
634 
635  // Can I assume that the path is always in "" on the last line
636  size_t pos2 = retval.rfind ('"');
637  size_t pos1 = retval.rfind ('"', pos2 - 1);
638  retval = retval.substr (pos1 + 1, pos2 - pos1 - 1);
639 
640  SETOPTR (CURLOPT_HEADERFUNCTION, 0);
641  SETOPTR (CURLOPT_WRITEHEADER, 0);
642  SETOPTR (CURLOPT_POSTQUOTE, 0);
643 
644  return retval;
645  }
646 
647  void http_get (const Array<std::string>& param)
648  {
649  http_action (param, "get");
650  }
651 
652  void http_post (const Array<std::string>& param)
653  {
654  http_action (param, "post");
655  }
656 
657  void http_action (const Array<std::string>& param, const std::string& action)
658  {
660 
661  std::string query_string;
662 
663  query_string = form_query_string (param);
664 
665  if (action.empty () || action == "get")
666  {
667  if (! query_string.empty ())
668  m_url += '?' + query_string;
669 
670  SETOPT (CURLOPT_URL, m_url.c_str ());
671  }
672  else if (action == "post" || action == "put" || action == "delete")
673  {
674  SETOPT (CURLOPT_POSTFIELDS, query_string.c_str ());
675 
676  if (action == "put")
677  {
678  SETOPT (CURLOPT_CUSTOMREQUEST, "PUT");
679  }
680 
681  if (action == "delete")
682  {
683  SETOPT (CURLOPT_CUSTOMREQUEST, "DELETE");
684  }
685 
686  SETOPT (CURLOPT_URL, m_url.c_str ());
687  }
688  else
689  {
690  m_ok = false;
691  m_errmsg = "curl_transfer: unknown http action";
692  }
693 
694  if (m_ok)
695  perform ();
696  }
697 
698  void cookie_jar (const std::string& filename)
699  {
700  SETOPT (CURLOPT_COOKIEJAR, filename.c_str ());
701 
702  SETOPT (CURLOPT_COOKIEFILE, filename.c_str ());
703  }
704 
705  // Sets the header fields in a transfer. Input should be in the form
706  // of an array of strings with pairs of keys and values together
708  {
709  struct curl_slist *slist = nullptr;
710 
711  unwind_protect frame;
712 
713  frame.add_fcn (curl_slist_free_all, slist);
714 
715  if (param.numel () >= 2)
716  {
717  for (int i = 0; i < param.numel (); i += 2)
718  {
719  std::string header = param(i) + ": " + param(i+1);
720 
721  slist = curl_slist_append (slist, header.c_str ());
722  }
723 
724  SETOPT (CURLOPT_HTTPHEADER, slist);
725  }
726  }
727 
728  // Sets and sends the form data associated with a transfer.
729  // Input should be an array of strings with each pair of strings
730  // corresponding to the fieldname and it's value.
731  // To attach a file, you should use 'file' as the fieldname with the
732  // path of the file as its value.
733  void form_data_post (const Array<std::string>& param)
734  {
735  struct curl_httppost *post = nullptr, *last = nullptr;
736 
737  SETOPT (CURLOPT_URL, m_host_or_url.c_str ());
738 
739  unwind_protect frame;
740 
741  frame.add_fcn (curl_formfree, post);
742 
743  if (param.numel () >= 2)
744  {
745  for (int i = 0; i < param.numel (); i += 2)
746  {
747  std::string name = param(i);
748  std::string data = param(i+1);
749 
750  if (name == "file")
751  curl_formadd (&post, &last, CURLFORM_COPYNAME, name.c_str (),
752  CURLFORM_FILE, data.c_str (), CURLFORM_END);
753  else
754  curl_formadd(&post, &last, CURLFORM_COPYNAME, name.c_str (),
755  CURLFORM_COPYCONTENTS, data.c_str (), CURLFORM_END);
756  }
757 
758  SETOPT (CURLOPT_HTTPPOST, post);
759  }
760 
761  perform ();
762  }
763 
764  // Sets the various options specified by weboptions object.
765  void set_weboptions (const struct weboptions& options)
766  {
767  // Remove this after completing fixmes.
768  std::string temp = "";
769 
771 
772  SETOPT (CURLOPT_TIMEOUT, options.Timeout);
773 
774  if (! options.UserAgent.empty ())
775  SETOPT (CURLOPT_USERAGENT, options.UserAgent.c_str ());
776 
777  if (! options.Username.empty ())
778  {
779  if (! options.Password.empty ())
780  {
781  std::string tmp = options.Username + ":" + options.Password;
782  SETOPT (CURLOPT_USERPWD, tmp.c_str ());
783  }
784  else
785  {
786  std::string tmp = options.Username + ":";
787  SETOPT (CURLOPT_USERPWD, tmp.c_str ());
788  }
789  }
790 
791  // Unimplemented. Only for MATLAB compatibility.
792  if (! options.ContentReader.empty ())
793  temp = options.ContentReader;
794 
795  // Unimplemented. Only for MATLAB compatibility.
796  if (! options.ArrayFormat.empty ())
797  temp = options.ArrayFormat;
798 
799  // Unimplemented. Only for MATLAB compatibility.
800  if (! options.CertificateFilename.empty ())
801  temp = options.CertificateFilename;
802  }
803 
804  private:
805 
806  // Pointer to cURL object.
807  CURL *m_curl;
808 
809  // cURL error code.
810  CURLcode m_errnum;
811 
812  // The cURL library changed the curl_easy_setopt call to make an
813  // internal copy of string parameters in version 7.17.0. Prior
814  // versions only held a pointer to a string provided by the caller
815  // that must persist for the lifetime of the CURL handle.
816  //
817  // The associated API did not change, only the behavior of the library
818  // implementing the function call.
819  //
820  // To be compatible with any version of cURL, the caller must keep a
821  // copy of all string parameters associated with a CURL handle until
822  // the handle is released. The curl_handle::curl_handle_rep class
823  // contains the pointer to the CURL handle and so is the best
824  // candidate for storing the strings as well. (bug #36717)
825  std::string m_url;
826  std::string m_userpwd;
827 
828  void init (const std::string& user, const std::string& passwd,
829  std::istream& is, std::ostream& os)
830  {
831  // No data transfer by default
832  SETOPT (CURLOPT_NOBODY, 1);
833 
834  // Set the username and password
835  m_userpwd = user;
836  if (! passwd.empty ())
837  m_userpwd += ':' + passwd;
838  if (! m_userpwd.empty ())
839  SETOPT (CURLOPT_USERPWD, m_userpwd.c_str ());
840 
841  // Define our callback to get called when there's data to be written.
842  SETOPT (CURLOPT_WRITEFUNCTION, write_data);
843 
844  // Set a pointer to our struct to pass to the callback.
845  SETOPT (CURLOPT_WRITEDATA, static_cast<void *> (&os));
846 
847  // Define our callback to get called when there's data to be read
848  SETOPT (CURLOPT_READFUNCTION, read_data);
849 
850  // Set a pointer to our struct to pass to the callback.
851  SETOPT (CURLOPT_READDATA, static_cast<void *> (&is));
852 
853  // Follow redirects.
854  SETOPT (CURLOPT_FOLLOWLOCATION, true);
855 
856  // Don't use EPSV since connecting to sites that don't support it
857  // will hang for some time (3 minutes?) before moving on to try PASV
858  // instead.
859  SETOPT (CURLOPT_FTP_USE_EPSV, false);
860 
861  // Set the user agent for the curl request
862  // Needed by mediaWiki API.
863  curl_version_info_data * data = curl_version_info(CURLVERSION_NOW);
864  const char *lib_ver = data->version;
865  std::string user_agent
866  ("GNU Octave/"
867  + std::string (OCTAVE_VERSION)
868  + " (https://www.gnu.org/software/octave/ ; help@octave.org) libcurl/"
869  + std::string (lib_ver));
870 
871  SETOPT (CURLOPT_USERAGENT, user_agent.c_str ());
872 
873  SETOPT (CURLOPT_NOPROGRESS, true);
874  SETOPT (CURLOPT_FAILONERROR, true);
875 
876  SETOPT (CURLOPT_POSTQUOTE, 0);
877  SETOPT (CURLOPT_QUOTE, 0);
878  }
879 
880  std::string form_query_string (const Array<std::string>& param)
881  {
882  std::ostringstream query;
883 
884  if (param.numel () >= 2)
885  for (int i = 0; i < param.numel (); i += 2)
886  {
887  std::string name = param(i);
888  std::string text = param(i+1);
889 
890  // Encode strings.
891  char *enc_name = curl_easy_escape (m_curl, name.c_str (),
892  name.length ());
893  char *enc_text = curl_easy_escape (m_curl, text.c_str (),
894  text.length ());
895 
896  query << enc_name << '=' << enc_text;
897 
898  curl_free (enc_name);
899  curl_free (enc_text);
900 
901  if (i < param.numel ()-2)
902  query << '&';
903  }
904 
905  query.flush ();
906 
907  return query.str ();
908  }
909 
910  void ftp_file_or_dir_action (const std::string& file_or_dir,
911  const std::string& action)
912  {
913  struct curl_slist *slist = nullptr;
914 
915  unwind_protect frame;
916 
917  frame.add_fcn (curl_slist_free_all, slist);
918 
919  std::string cmd = action + ' ' + file_or_dir;
920 
921  slist = curl_slist_append (slist, cmd.c_str ());
922 
923  SETOPT (CURLOPT_POSTQUOTE, slist);
924 
925  perform ();
926 
927  if (! good ())
928  return;
929 
930  SETOPT (CURLOPT_POSTQUOTE, 0);
931  }
932  };
933 
934 #undef SETOPT
935 
936 #endif
937 
938 #if defined (HAVE_CURL)
939 # define REP_CLASS curl_transfer
940 #else
941 # define REP_CLASS base_url_transfer
942 #endif
943 
944  url_transfer::url_transfer (void) : m_rep (new REP_CLASS ())
945  { }
946 
947  url_transfer::url_transfer (const std::string& host, const std::string& user,
948  const std::string& passwd, std::ostream& os)
949  : m_rep (new REP_CLASS (host, user, passwd, os))
950  { }
951 
952  url_transfer::url_transfer (const std::string& url, std::ostream& os)
953  : m_rep (new REP_CLASS (url, os))
954  { }
955 
956 #undef REP_CLASS
957 
958 }
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
void add_fcn(void(*fcn)(Params...), Args &&... args)
static void delete_file(const std::string &file)
Definition: url-transfer.cc:74
virtual void mkdir(const std::string &)
Definition: url-transfer.h:121
static void reset_path(base_url_transfer *curl_xfer)
Definition: url-transfer.h:63
std::ostream * m_curr_ostream
Definition: url-transfer.h:174
string_vector mput_directory(const std::string &base, const std::string &directory)
virtual void put(const std::string &, std::istream &)
Definition: url-transfer.h:126
std::istream * m_curr_istream
Definition: url-transfer.h:173
virtual void get(const std::string &, std::ostream &)
Definition: url-transfer.h:129
virtual void cwd(const std::string &)
Definition: url-transfer.h:115
virtual void get_fileinfo(const std::string &, double &, time_t &, bool &)
Definition: url-transfer.h:142
virtual string_vector list(void)
Definition: url-transfer.h:140
void mget_directory(const std::string &directory, const std::string &target)
Definition: url-transfer.cc:80
bool good(void) const
Definition: url-transfer.h:91
void set_header_fields(const Array< std::string > &param)
void set_weboptions(const struct weboptions &options)
void http_action(const Array< std::string > &param, const std::string &action)
void put(const std::string &file, std::istream &is)
void cookie_jar(const std::string &filename)
std::string lasterror(void) const
void get(const std::string &file, std::ostream &os)
curl_transfer & operator=(const curl_transfer &)=delete
void http_get(const Array< std::string > &param)
void init(const std::string &user, const std::string &passwd, std::istream &is, std::ostream &os)
void mkdir(const std::string &path)
void get_fileinfo(const std::string &filename, double &filesize, time_t &filetime, bool &fileisdir)
void ftp_file_or_dir_action(const std::string &file_or_dir, const std::string &action)
curl_transfer(const std::string &host, const std::string &user_arg, const std::string &passwd, std::ostream &os)
std::string pwd(void)
std::istream & set_istream(std::istream &is)
string_vector list(void)
void cwd(const std::string &path)
void rename(const std::string &oldname, const std::string &newname)
std::ostream & set_ostream(std::ostream &os)
void http_post(const Array< std::string > &param)
void rmdir(const std::string &path)
curl_transfer(const std::string &url_str, std::ostream &os)
void form_data_post(const Array< std::string > &param)
void del(const std::string &file)
std::string form_query_string(const Array< std::string > &param)
curl_transfer(const curl_transfer &)=delete
bool eof(void) const
Definition: oct-stream.cc:7267
octave_value read(const Array< double > &size, octave_idx_type block_size, oct_data_conv::data_type input_type, oct_data_conv::data_type output_type, octave_idx_type skip, mach_info::float_format flt_fmt, octave_idx_type &count)
Definition: oct-stream.cc:6580
octave_idx_type write(const octave_value &data, octave_idx_type block_size, oct_data_conv::data_type output_type, octave_idx_type skip, mach_info::float_format flt_fmt)
Definition: oct-stream.cc:6777
bool is_dir(void) const
Definition: file-stat.cc:65
bool exists(void) const
Definition: file-stat.h:147
static std::string getenv(const std::string &name)
Definition: oct-env.cc:271
string_vector & append(const std::string &s)
Definition: str-vec.cc:110
octave_idx_type numel(void) const
Definition: str-vec.h:100
QString path
QString name
#define OCTAVE_VERSION
Definition: main.in.cc:52
octave_idx_type n
Definition: mx-inlines.cc:753
std::string dir_sep_str(void)
Definition: file-ops.cc:243
int mkdir(const std::string &nm, mode_t md)
Definition: file-ops.cc:404
std::ifstream ifstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:381
int unlink(const std::string &name)
Definition: file-ops.cc:626
std::ofstream ofstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:395
bool get_dirlist(const std::string &dirname, string_vector &dirlist, std::string &msg)
Definition: lo-sysdep.cc:101
static size_t throw_away(void *, size_t size, size_t nmemb, void *)
static int write_data(void *buffer, size_t size, size_t nmemb, void *streamp)
static int read_data(void *buffer, size_t size, size_t nmemb, void *streamp)
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
#define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE
Definition: quit.h:280
#define END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE
Definition: quit.h:284
std::string UserAgent
Definition: url-transfer.h:44
std::string Password
Definition: url-transfer.h:47
std::string ArrayFormat
Definition: url-transfer.h:51
std::string ContentReader
Definition: url-transfer.h:49
std::string Username
Definition: url-transfer.h:46
Array< std::string > HeaderFields
Definition: url-transfer.h:48
std::string CertificateFilename
Definition: url-transfer.h:52
#define SETOPT(option, parameter)
#define SETOPTR(option, parameter)
#define REP_CLASS