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