libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
getdap4.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1997-1999
27// Please read the full copyright statement in the file COPYRIGHT_URI.
28//
29// Authors:
30// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31
32// This is the source to `getdap'; a simple tool to exercise the Connect
33// class. It can be used to get naked URLs as well as the DAP2 DAS and DDS
34// objects. jhrg.
35
36#include "config.h"
37
38#ifdef WIN32
39#include <fcntl.h>
40#include <io.h>
41#endif
42
43#include <cstring>
44#include <sstream>
45#include <string>
46#include <unistd.h> // getopt
47
48#include "D4BaseTypeFactory.h"
49#include "D4Connect.h"
50#include "D4Group.h"
51#include "D4Sequence.h"
52#include "DMR.h"
53#include "HTTPConnect.h"
54#include "RCReader.h"
55#include "StdinResponse.h"
56#include "XMLWriter.h"
57
58using namespace std;
59using namespace libdap;
60
61const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
62
63static void usage(const string &) {
64 const char *message = R"(
65 Usage: getdap4 [dD vVmzsM][-c <expr>][-m <num>] <url> [<url> ...]
66 getdap4 [dD vVmzsM][-c <expr>][-m <num>] <file> [<file> ...]
67
68 In the first form of the command, dereference the URL and perform
69 the requested operations. This includes routing the returned
70 information through the DAP processing library (parsing the
71 returned objects, et c.). If none of d, or D are used with a URL,
72 then the DAP library routines are NOT used and the URLs contents
73 are dumped to standard output.
74
75 Note: If the URL contains a query string the query string will be
76 preserved in the request. However, if the query string contains
77 DAP4 keys they may interfere with the operation of getdap4. A
78 warning will be written to stderr when getdap4 identifies the
79 presence of a DAP4 query key in the submitted URL's query string.
80
81 In the second form of the command, assume the files are DAP4 data
82 responses (stored in files or read from pipes)
83
84 Options:
85 d: For each URL, get the (DAP4) DMR object. Does not get data.
86 D: For each URL, get the DAP4 Data response.
87
88 v: Verbose output.
89 V: Version of this client
90 i: For each URL, get the server version.
91 m: Request the same URL <num> times.
92 z: Ask the server to compress data.
93 s: Print Sequences using numbered rows.
94 M: Assume data read from a file has no MIME headers; use only
95 with files
96
97 c: <expr> is a constraint expression. Used with -d/D
98 NB: You can use a `?' for the CE also.
99 S: Used in conjunction with -d and will report the total size
100 of the data referenced in the DMR.)";
101
102 cerr << message << endl;
103}
104
105// Used for raw http access/transfer
106bool read_data(FILE *fp) {
107 if (!fp) {
108 fprintf(stderr, "getdap4: Whoa!!! Null stream pointer.\n");
109 return false;
110 }
111 // Changed from a loop that used getc() to one that uses fread(). getc()
112 // worked fine for transfers of text information, but *not* for binary
113 // transfers. fread() will handle both.
114 char c = 0;
115 while (fp && !feof(fp) && fread(&c, 1, 1, fp))
116 printf("%c", c); // stick with stdio
117
118 return true;
119}
120
121static void read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data,
122 bool get_dmr) {
123 if (mime_headers) {
124 if (get_dap4_data)
125 url->read_data(dmr, r);
126 else if (get_dmr)
127 url->read_dmr(dmr, r);
128 else
129 throw Error("Only supports Data or DMR responses");
130 } else {
131 if (get_dap4_data)
132 url->read_data_no_mime(dmr, r);
133 else if (get_dmr)
134 url->read_dmr_no_mime(dmr, r);
135 else
136 throw Error("Only supports Data or DMR responses");
137 }
138}
139
140static void print_group_data(D4Group *g, bool print_rows = false) {
141 for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
142 if (print_rows && (*i)->type() == dods_sequence_c)
143 dynamic_cast<D4Sequence &>(**i).print_val_by_rows(cout);
144 else
145 (*i)->print_val(cout);
146 }
147
148 for (D4Group::groupsIter gi = g->grp_begin(), ge = g->grp_end(); gi != ge; ++gi) {
149 print_group_data(*gi, print_rows);
150 }
151}
152
153static void print_data(DMR &dmr, bool print_rows = false) {
154 cout << "The data:" << endl;
155
156 D4Group *g = dmr.root();
157
158 print_group_data(g, print_rows);
159
160 cout << endl << flush;
161}
162
173unsigned long long get_size(D4Group *grp, bool constrained = false) {
174 unsigned long long w = 0;
175
176 for (auto var_itr = grp->var_begin(); var_itr != grp->var_end(); var_itr++) {
177 if (constrained) {
178 if ((*var_itr)->send_p())
179 w += (*var_itr)->width(constrained);
180 } else {
181 w += (*var_itr)->width(constrained);
182 }
183 }
184 for (auto grp_itr = grp->grp_begin(); grp_itr != grp->grp_end(); grp_itr++) {
185 w += get_size(*grp_itr, constrained);
186 }
187
188 return w;
189}
190
191unsigned long long get_size(DMR &dmr, bool constrained = false) { return get_size(dmr.root(), constrained); }
192
193int main(int argc, char *argv[]) {
194 int option_char;
195
196 bool get_dmr = false;
197 bool get_dap4_data = false;
198 bool verbose = false;
199 bool accept_deflate = false;
200 bool print_rows = false;
201 bool mime_headers = true;
202 bool report_errors = false;
203 int times = 1;
204 int dap_client_major = 4;
205 int dap_client_minor = 0;
206 string expr;
207 bool compute_size = false;
208
209#ifdef WIN32
210 _setmode(_fileno(stdout), _O_BINARY);
211#endif
212
213 while ((option_char = getopt(argc, argv, "dDvVrm:Mzsc:S")) != -1) {
214 switch (option_char) {
215 case 'd':
216 get_dmr = true;
217 break;
218 case 'D':
219 get_dap4_data = true;
220 break;
221 case 'v':
222 verbose = true;
223 break;
224 case 'V':
225 cerr << "getdap4 version: " << version << endl;
226 exit(0);
227 case 'S':
228 compute_size = true;
229 break;
230 case 'r':
231 report_errors = true;
232 break;
233 case 'm':
234 times = atoi(optarg);
235 break;
236 case 'z':
237 accept_deflate = true;
238 break;
239 case 's':
240 print_rows = true;
241 break;
242 case 'M':
243 mime_headers = false;
244 break;
245 case 'c':
246 expr = optarg;
247 break;
248 case 'h':
249 case '?':
250 default:
251 usage(argv[0]);
252 exit(1);
253 }
254 }
255
256 D4Connect *url = nullptr;
257 try {
258 // If after processing all the command line options there is nothing
259 // left (no URL or file) assume that we should read from stdin.
260 for (int i = optind; i < argc; ++i) {
261 if (verbose)
262 cerr << "Fetching: " << argv[i] << endl;
263
264 string name = argv[i];
265 url = new D4Connect(name);
266
267 // This overrides the value set in the .dodsrc file.
268 if (accept_deflate)
269 url->set_accept_deflate(accept_deflate);
270
271 if (dap_client_major > 2)
272 url->set_xdap_protocol(dap_client_major, dap_client_minor);
273
274 if (url->is_local()) {
275 if (verbose)
276 cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
277
278 try {
279 D4BaseTypeFactory factory;
280 DMR dmr(&factory);
281
282 if (strcmp(argv[i], "-") == 0) {
283 StdinResponse r(cin);
284
285 if (!r.get_cpp_stream())
286 throw Error("Could not open standard input.");
287
288 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
289 } else {
290 fstream f(argv[i], std::ios_base::in);
291 if (!f.is_open() || f.bad() || f.eof())
292 throw Error((string) "Could not open: " + argv[i]);
293
294 Response r(&f, 0);
295
296 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
297 }
298
299 if (verbose)
300 cerr << "DAP version: " << url->get_protocol().c_str()
301 << " Server version: " << url->get_version().c_str() << endl;
302
303 // Always write the DMR
304 XMLWriter xml;
305 dmr.print_dap4(xml);
306 cout << xml.get_doc() << endl;
307
308 if (get_dap4_data)
309 print_data(dmr, print_rows);
310 } catch (Error &e) {
311 cerr << "Error: " << e.get_error_message() << endl;
312 delete url;
313 url = nullptr;
314 if (report_errors)
315 return EXIT_FAILURE;
316 }
317 } else if (get_dmr) {
318 for (int j = 0; j < times; ++j) {
319 D4BaseTypeFactory factory;
320 DMR dmr(&factory);
321 try {
322 url->request_dmr(dmr, expr);
323
324 if (verbose) {
325 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
326 << endl;
327 cout << "DMR:" << endl;
328 }
329
330 XMLWriter xml;
331 dmr.print_dap4(xml);
332 cout << xml.get_doc() << endl;
333 if (compute_size) {
334 cout << "DMR References " << get_size(dmr) << " bytes of data," << endl;
335 }
336 } catch (Error &e) {
337 cerr << e.get_error_message() << endl;
338 if (report_errors)
339 return EXIT_FAILURE;
340 continue; // Goto the next URL or exit the loop.
341 }
342 }
343 } else if (get_dap4_data) {
344 for (int j = 0; j < times; ++j) {
345 D4BaseTypeFactory factory;
346 DMR dmr(&factory);
347 try {
348 url->request_dap4_data(dmr, expr);
349
350 if (verbose) {
351 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
352 << endl;
353 cout << "DMR:" << endl;
354 }
355
356 XMLWriter xml;
357 dmr.print_dap4(xml);
358 cout << xml.get_doc() << endl;
359
360 print_data(dmr, print_rows);
361 } catch (Error &e) {
362 cerr << e.get_error_message() << endl;
363 if (report_errors)
364 return EXIT_FAILURE;
365 continue; // Goto the next URL or exit the loop.
366 }
367 }
368 } else {
369 HTTPConnect http(RCReader::instance());
370
371 // This overrides the value set in the .dodsrc file.
372 if (accept_deflate)
373 http.set_accept_deflate(accept_deflate);
374
375 if (dap_client_major > 2)
376 url->set_xdap_protocol(dap_client_major, dap_client_minor);
377
378 string url_string = argv[i];
379 for (int j = 0; j < times; ++j) {
380 try {
381 HTTPResponse *r = http.fetch_url(url_string);
382 if (verbose) {
383 vector<string> *headers = r->get_headers();
384 copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
385 }
386 if (!read_data(r->get_stream())) {
387 continue;
388 }
389 delete r;
390 r = 0;
391 } catch (Error &e) {
392 cerr << e.get_error_message() << endl;
393 if (report_errors)
394 return EXIT_FAILURE;
395 continue;
396 }
397 }
398 }
399
400 delete url;
401 url = nullptr;
402 }
403 } catch (Error &e) {
404 delete url;
405 if (e.get_error_code() == malformed_expr) {
406 cerr << e.get_error_message() << endl;
407 usage(argv[0]);
408 } else {
409 cerr << e.get_error_message() << endl;
410 }
411
412 cerr << "Exiting." << endl;
413 return EXIT_FAILURE;
414 } catch (exception &e) {
415 delete url;
416 cerr << "C++ library exception: " << e.what() << endl;
417 cerr << "Exiting." << endl;
418 return EXIT_FAILURE;
419 }
420
421 return EXIT_SUCCESS;
422}
Vars_iter var_begin()
std::string get_protocol()
Definition D4Connect.h:97
void set_accept_deflate(bool deflate)
Definition D4Connect.cc:467
void set_xdap_protocol(int major, int minor)
Definition D4Connect.cc:477
std::string get_version()
Definition D4Connect.h:92
groupsIter grp_begin()
Get an iterator to the start of the values.
Definition D4Group.h:116
groupsIter grp_end()
Get an iterator to the end of the values.
Definition D4Group.h:119
Holds a sequence.
Definition D4Sequence.h:131
D4Group * root()
Definition DMR.cc:228
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition DMR.cc:306
A class for error processing.
Definition Error.h:92
ErrorCode get_error_code() const
Definition Error.cc:189
std::string get_error_message() const
Definition Error.cc:212
Encapsulate a response read from stdin.
top level DAP object to house generic methods
Definition AISConnect.cc:30