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