GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
urlwrite.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 <string>
31#include <fstream>
32#include <iomanip>
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 "oct-handle.h"
40#include "glob-match.h"
41#include "url-transfer.h"
42
43#include "defun.h"
44#include "error.h"
45#include "interpreter.h"
46#include "oct-map.h"
47#include "oct-refcount.h"
48#include "ov-cell.h"
49#include "ov-classdef.h"
50#include "ovl.h"
51#include "pager.h"
52#include "unwind-prot.h"
53#include "url-handle-manager.h"
54
56
57DEFUN (urlwrite, args, nargout,
58 doc: /* -*- texinfo -*-
59@deftypefn {} {} urlwrite (@var{url}, @var{localfile})
60@deftypefnx {} {@var{f} =} urlwrite (@var{url}, @var{localfile})
61@deftypefnx {} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})
62@deftypefnx {} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})
63Download a remote file specified by its @var{url} and save it as
64@var{localfile}.
65
66For example:
67
68@example
69@group
70urlwrite ("http://ftp.octave.org/pub/README",
71 "README.txt");
72@end group
73@end example
74
75The full path of the downloaded file is returned in @var{f}.
76
77The variable @var{success} is 1 if the download was successful,
78otherwise it is 0 in which case @var{message} contains an error message.
79
80If no output argument is specified and an error occurs, then the error is
81signaled through Octave's error handling mechanism.
82
83This function uses libcurl. The curl library supports, among others, the HTTP,
84FTP, and FILE protocols. Username and password may be specified in the URL,
85for example:
86
87@example
88@group
89urlwrite ("http://username:password@@example.com/file.txt",
90 "file.txt");
91@end group
92@end example
93
94GET and POST requests can be specified by @var{method} and @var{param}.
95The parameter @var{method} is either @samp{get} or @samp{post} and
96@var{param} is a cell array of parameter and value pairs.
97For example:
98
99@example
100@group
101urlwrite ("http://www.google.com/search", "search.html",
102 "get", @{"query", "octave"@});
103@end group
104@end example
105@seealso{urlread}
106@end deftypefn */)
107{
108 int nargin = args.length ();
109
110 // verify arguments
111 if (nargin != 2 && nargin != 4)
112 print_usage ();
113
114 std::string url = args(0).xstring_value ("urlwrite: URL must be a string");
115
116 // name to store the file if download is successful
117 std::string filename = args(1).xstring_value ("urlwrite: LOCALFILE must be a string");
118
119 std::string method;
120 Array<std::string> param;
121
122 if (nargin == 4)
123 {
124 method = args(2).xstring_value ("urlwrite: METHOD must be a string");
125
126 if (method != "get" && method != "post")
127 error (R"(urlwrite: METHOD must be "get" or "post")");
128
129 param = args(3).xcellstr_value ("urlwrite: parameters (PARAM) for get and post requests must be given as a cell array of strings");
130
131 if (param.numel () % 2 == 1)
132 error ("urlwrite: number of elements in PARAM must be even");
133 }
134
135 // The file should only be deleted if it doesn't initially exist, we
136 // create it, and the download fails. We use unwind_protect to do
137 // it so that the deletion happens no matter how we exit the function.
138
139 std::ofstream ofile =
140 sys::ofstream (filename.c_str (), std::ios::out | std::ios::binary);
141
142 if (! ofile.is_open ())
143 error ("urlwrite: unable to open file");
144
145 int(*unlink_fptr)(const std::string&) = sys::unlink;
146 unwind_action_safe unlink_action (unlink_fptr, filename);
147
148 url_transfer url_xfer (url, ofile);
149
150 octave_value_list retval;
151
152 if (! url_xfer.is_valid ())
153 error ("support for URL transfers was disabled when Octave was built");
154
155 url_xfer.http_action (param, method);
156
157 ofile.close ();
158
159 if (url_xfer.good ())
160 unlink_action.discard ();
161
162 if (nargout > 0)
163 {
164 if (url_xfer.good ())
165 retval = ovl (sys::env::make_absolute (filename), true, "");
166 else
167 retval = ovl ("", false, url_xfer.lasterror ());
168 }
169
170 if (nargout < 2 && ! url_xfer.good ())
171 error ("urlwrite: %s", url_xfer.lasterror ().c_str ());
172
173 return retval;
174}
175
176DEFUN (urlread, args, nargout,
177 doc: /* -*- texinfo -*-
178@deftypefn {} {@var{s} =} urlread (@var{url})
179@deftypefnx {} {[@var{s}, @var{success}] =} urlread (@var{url})
180@deftypefnx {} {[@var{s}, @var{success}, @var{message}] =} urlread (@var{url})
181@deftypefnx {} {[@dots{}] =} urlread (@var{url}, @var{method}, @var{param})
182Download a remote file specified by its @var{url} and return its content
183in string @var{s}.
184
185For example:
186
187@example
188s = urlread ("http://ftp.octave.org/pub/README");
189@end example
190
191The variable @var{success} is 1 if the download was successful,
192otherwise it is 0 in which case @var{message} contains an error
193message.
194
195If no output argument is specified and an error occurs, then the error is
196signaled through Octave's error handling mechanism.
197
198This function uses libcurl. The curl library supports, among others, the HTTP,
199FTP, and FILE protocols. Username and password may be specified in the URL@.
200For example:
201
202@example
203s = urlread ("http://user:password@@example.com/file.txt");
204@end example
205
206GET and POST requests can be specified by @var{method} and @var{param}.
207The parameter @var{method} is either @samp{get} or @samp{post} and
208@var{param} is a cell array of parameter and value pairs.
209For example:
210
211@example
212@group
213s = urlread ("http://www.google.com/search",
214 "get", @{"query", "octave"@});
215@end group
216@end example
217@seealso{urlwrite}
218@end deftypefn */)
219{
220 int nargin = args.length ();
221
222 // verify arguments
223 if (nargin != 1 && nargin != 3)
224 print_usage ();
225
226 std::string url = args(0).xstring_value ("urlread: URL must be a string");
227
228 std::string method;
229 Array<std::string> param;
230
231 if (nargin == 3)
232 {
233 method = args(1).xstring_value ("urlread: METHOD must be a string");
234
235 if (method != "get" && method != "post")
236 error (R"(urlread: METHOD must be "get" or "post")");
237
238 param = args(2).xcellstr_value ("urlread: parameters (PARAM) for get and post requests must be given as a cell array of strings");
239
240 if (param.numel () % 2 == 1)
241 error ("urlread: number of elements in PARAM must be even");
242 }
243
244 std::ostringstream buf;
245
246 url_transfer url_xfer = url_transfer (url, buf);
247
248 if (! url_xfer.is_valid ())
249 error ("support for URL transfers was disabled when Octave was built");
250
251 url_xfer.http_action (param, method);
252
253 if (nargout < 2 && ! url_xfer.good ())
254 error ("urlread: %s", url_xfer.lasterror ().c_str ());
255
256 octave_value_list retval (std::max (1, std::min (nargout, 3)));
257
258 retval(0) = buf.str ();
259 if (nargout > 1)
260 retval(1) = url_xfer.good ();
261 if (nargout > 2)
262 retval(2) = url_xfer.good () ? "" : url_xfer.lasterror ();
263
264 return retval;
265}
266
267DEFUN (__restful_service__, args, nargout,
268 doc: /* -*- texinfo -*-
269@deftypefn {} {@var{response} =} __restful_service__ (@var{url}, @var{param}, @var{weboptions})
270Undocumented internal function.
271@end deftypefn */)
272{
273 int nargin = args.length ();
274
275 if (nargin < 1)
276 print_usage ();
277
278 std::string url = args(0).xstring_value ("__restful_service__: URL must be a string");
279
280 std::ostringstream content;
281
282 url_transfer url_xfer (url, content);
283
284 if (! url_xfer.is_valid ())
285 error ("support for URL transfers was disabled when Octave was built");
286
287 Array<std::string> param = args(1).cellstr_value ();
288
289 std::string data, method;
290
291 struct weboptions options;
292
293 cdef_object object
294 = args (nargin - 1).classdef_object_value () -> get_object ();
295
296 // We could've used object.map_value () instead to return a map but that
297 // shows a warning about about overriding access restrictions.
298 // Nevertheless, we are keeping checking that here if the keys are not
299 // equal to "delete" and "display", getting away with the warning.
300 string_vector keys = object.map_keys ();
301
302 for (int i = 0; i < keys.numel (); i++)
303 {
304 if (keys(i) == "Timeout")
305 {
306 float timeout = object.get (keys(i)).float_value ();
307 options.Timeout = static_cast<long> (timeout * 1000);
308 }
309
310 if (keys(i) == "HeaderFields")
311 {
312 options.HeaderFields = object.get (keys(i)).cellstr_value ();
313 }
314
315 // FIXME: 'delete' and 'display', auto-generated, probably by cdef_object
316 // class? Remaining fields have already been adjusted elsewhere in the
317 // m-script. Set 'value' as the Value of the Key wherever it's a string.
318 if (keys(i) != "Timeout" && keys(i) != "HeaderFields"
319 && keys(i) != "delete" && keys(i) != "display")
320 {
321 std::string value = object.get (keys(i)).string_value ();
322
323 if (keys(i) == "UserAgent")
324 options.UserAgent = value;
325
326 if (keys(i) == "Username")
327 options.Username = value;
328
329 if (keys(i) == "Password")
330 options.Password = value;
331
332 if (keys(i) == "ContentReader")
333 // Unimplemented. Only for MATLAB compatibility.
334 options.ContentReader = "";
335
336 if (keys(i) == "RequestMethod")
337 method = value;
338
339 if (keys(i) == "ArrayFormat")
340 options.ArrayFormat = value;
341
342 if (keys(i) == "CertificateFilename")
343 options.CertificateFilename = "";
344 }
345 }
346
347 url_xfer.set_weboptions (options);
348
349 url_xfer.http_action (param, method);
350
351 if (nargout < 2 && ! url_xfer.good ())
352 error ("__restful_service__: %s", url_xfer.lasterror ().c_str ());
353
354 return ovl (content.str ());
355}
356
357OCTAVE_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
octave_idx_type length() const
Definition ovl.h:111
octave_idx_type numel() const
Definition str-vec.h:98
void set_weboptions(const struct weboptions &param)
bool is_valid() const
std::string lasterror() const
void http_action(const Array< std::string > &param, const std::string &action)
bool good() const
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
void error(const char *fmt,...)
Definition error.cc:1003
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
std::string UserAgent
std::string ArrayFormat
std::string ContentReader
Array< std::string > HeaderFields
std::string Password
std::string CertificateFilename
std::string Username