libdap Updated for version 3.20.10
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 <io.h>
40#include <fcntl.h>
41#endif
42
43#include <cstring>
44#include <string>
45#include <sstream>
46#include <unistd.h> // getopt
47
48#include "DMR.h"
49#include "XMLWriter.h"
50#include "D4BaseTypeFactory.h"
51#include "D4Group.h"
52#include "D4Sequence.h"
53#include "D4Connect.h"
54#include "StdinResponse.h"
55#include "HTTPConnect.h"
56#include "RCReader.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{
65 const char *message = R"(
66 Usage: getdap4 [dD vVmzsM][-c <expr>][-m <num>] <url> [<url> ...]
67 getdap4 [dD vVmzsM][-c <expr>][-m <num>] <file> [<file> ...]
68
69 In the first form of the command, dereference the URL and perform
70 the requested operations. This includes routing the returned
71 information through the DAP processing library (parsing the
72 returned objects, et c.). If none of d, or D are used with a URL,
73 then the DAP library routines are NOT used and the URLs contents
74 are dumped to standard output.
75
76 Note: If the URL contains a query string the query string will be
77 preserved in the request. However, if the query string contains
78 DAP4 keys they may interfere with the operation of getdap4. A
79 warning will be written to stderr when getdap4 identifies the
80 presence of a DAP4 query key in the submitted URL's query string.
81
82 In the second form of the command, assume the files are DAP4 data
83 responses (stored in files or read from pipes)
84
85 Options:
86 d: For each URL, get the (DAP4) DMR object. Does not get data.
87 D: For each URL, get the DAP4 Data response.
88
89 v: Verbose output.
90 V: Version of this client
91 i: For each URL, get the server version.
92 m: Request the same URL <num> times.
93 z: Ask the server to compress data.
94 s: Print Sequences using numbered rows.
95 M: Assume data read from a file has no MIME headers; use only
96 with files
97
98 c: <expr> is a constraint expression. Used with -d/D
99 NB: You can use a `?' for the CE also.
100 S: Used in conjunction with -d and will report the total size
101 of the data referenced in the DMR.)";
102
103 cerr << message << endl;
104}
105
106// Used for raw http access/transfer
107bool read_data(FILE *fp)
108{
109 if (!fp) {
110 fprintf(stderr, "getdap4: Whoa!!! Null stream pointer.\n");
111 return false;
112 }
113 // Changed from a loop that used getc() to one that uses fread(). getc()
114 // worked fine for transfers of text information, but *not* for binary
115 // transfers. fread() will handle both.
116 char c = 0;
117 while (fp && !feof(fp) && fread(&c, 1, 1, fp))
118 printf("%c", c); // stick with stdio
119
120 return true;
121}
122
123static void
124read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data, bool get_dmr)
125{
126 if (mime_headers) {
127 if (get_dap4_data)
128 url->read_data(dmr, r);
129 else if (get_dmr)
130 url->read_dmr(dmr, r);
131 else
132 throw Error("Only supports Data or DMR responses");
133 }
134 else {
135 if (get_dap4_data)
136 url->read_data_no_mime(dmr, r);
137 else if (get_dmr)
138 url->read_dmr_no_mime(dmr, r);
139 else
140 throw Error("Only supports Data or DMR responses");
141 }
142}
143
144static void print_group_data(D4Group *g, bool print_rows = false)
145{
146 for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
147 if (print_rows && (*i)->type() == dods_sequence_c)
148 dynamic_cast<D4Sequence &>(**i).print_val_by_rows(cout);
149 else
150 (*i)->print_val(cout);
151 }
152
153 for (D4Group::groupsIter gi = g->grp_begin(), ge = g->grp_end(); gi != ge; ++gi) {
154 print_group_data(*gi, print_rows);
155 }
156}
157
158static void print_data(DMR &dmr, bool print_rows = false)
159{
160 cout << "The data:" << endl;
161
162 D4Group *g = dmr.root();
163
164 print_group_data(g, print_rows);
165
166 cout << endl << flush;
167}
168
179unsigned long long get_size(D4Group *grp, bool constrained = false)
180{
181 unsigned long long w = 0;
182
183 for (auto var_itr = grp->var_begin(); var_itr != grp->var_end(); var_itr++) {
184 if (constrained) {
185 if ((*var_itr)->send_p())
186 w += (*var_itr)->width(constrained);
187 }
188 else {
189 w += (*var_itr)->width(constrained);
190 }
191 }
192 for (auto grp_itr = grp->grp_begin(); grp_itr != grp->grp_end(); grp_itr++) {
193 w += get_size(*grp_itr, constrained);
194 }
195
196 return w;
197}
198
199unsigned long long get_size(DMR &dmr, bool constrained = false)
200{
201 return get_size(dmr.root(), constrained);
202}
203
204
205int main(int argc, char *argv[])
206{
207 int option_char;
208
209 bool get_dmr = false;
210 bool get_dap4_data = false;
211 bool cexpr = false;
212 bool verbose = false;
213 bool multi = false;
214 bool accept_deflate = false;
215 bool print_rows = false;
216 bool mime_headers = true;
217 bool report_errors = false;
218 int times = 1;
219 int dap_client_major = 4;
220 int dap_client_minor = 0;
221 string expr = "";
222 bool compute_size = false;
223
224#ifdef WIN32
225 _setmode(_fileno(stdout), _O_BINARY);
226#endif
227
228 while ((option_char = getopt(argc, argv, "dDvVrm:Mzsc:S")) != -1) {
229 switch (option_char) {
230 case 'd':
231 get_dmr = true;
232 break;
233 case 'D':
234 get_dap4_data = true;
235 break;
236 case 'v':
237 verbose = true;
238 break;
239 case 'V':
240 cerr << "getdap4 version: " << version << endl;
241 exit(0);
242 case 'S':
243 compute_size = true;
244 break;
245 case 'r':
246 report_errors = true;
247 break;
248 case 'm':
249 multi = true;
250 times = atoi(optarg);
251 break;
252 case 'z':
253 accept_deflate = true;
254 break;
255 case 's':
256 print_rows = true;
257 break;
258 case 'M':
259 mime_headers = false;
260 break;
261 case 'c':
262 cexpr = true;
263 expr = optarg;
264 break;
265 case 'h':
266 case '?':
267 default:
268 usage(argv[0]);
269 exit(1);
270 }
271 }
272
273 D4Connect *url = nullptr;
274 try {
275 // If after processing all the command line options there is nothing
276 // left (no URL or file) assume that we should read from stdin.
277 for (int i = optind; i < argc; ++i) {
278 if (verbose)
279 cerr << "Fetching: " << argv[i] << endl;
280
281 string name = argv[i];
282 url = new D4Connect(name);
283
284 // This overrides the value set in the .dodsrc file.
285 if (accept_deflate)
286 url->set_accept_deflate(accept_deflate);
287
288 if (dap_client_major > 2)
289 url->set_xdap_protocol(dap_client_major, dap_client_minor);
290
291 if (url->is_local()) {
292 if (verbose)
293 cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
294
295 try {
296 D4BaseTypeFactory factory;
297 DMR dmr(&factory);
298
299 if (strcmp(argv[i], "-") == 0) {
300 StdinResponse r(cin);
301
302 if (!r.get_cpp_stream())
303 throw Error("Could not open standard input.");
304
305 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
306 }
307 else {
308 fstream f(argv[i], std::ios_base::in);
309 if (!f.is_open() || f.bad() || f.eof())
310 throw Error((string) "Could not open: " + argv[i]);
311
312 Response r(&f, 0);
313
314 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
315 }
316
317 if (verbose)
318 cerr << "DAP version: " << url->get_protocol().c_str() << " Server version: "
319 << url->get_version().c_str() << endl;
320
321 // Always write the DMR
322 XMLWriter xml;
323 dmr.print_dap4(xml);
324 cout << xml.get_doc() << endl;
325
326 if (get_dap4_data)
327 print_data(dmr, print_rows);
328 }
329 catch (Error &e) {
330 cerr << "Error: " << e.get_error_message() << endl;
331 delete url;
332 url = nullptr;
333 if (report_errors)
334 return EXIT_FAILURE;
335 }
336 }
337 else if (get_dmr) {
338 for (int j = 0; j < times; ++j) {
339 D4BaseTypeFactory factory;
340 DMR dmr(&factory);
341 try {
342 url->request_dmr(dmr, expr);
343
344 if (verbose) {
345 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
346 << endl;
347 cout << "DMR:" << endl;
348 }
349
350 XMLWriter xml;
351 dmr.print_dap4(xml);
352 cout << xml.get_doc() << endl;
353 if (compute_size) {
354 cout << "DMR References " << get_size(dmr) << " bytes of data," << endl;
355 }
356 }
357 catch (Error &e) {
358 cerr << e.get_error_message() << endl;
359 if (report_errors)
360 return EXIT_FAILURE;
361 continue; // Goto the next URL or exit the loop.
362 }
363 }
364 }
365 else if (get_dap4_data) {
366 for (int j = 0; j < times; ++j) {
367 D4BaseTypeFactory factory;
368 DMR dmr(&factory);
369 try {
370 url->request_dap4_data(dmr, expr);
371
372 if (verbose) {
373 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
374 << endl;
375 cout << "DMR:" << endl;
376 }
377
378 XMLWriter xml;
379 dmr.print_dap4(xml);
380 cout << xml.get_doc() << endl;
381
382 print_data(dmr, print_rows);
383 }
384 catch (Error &e) {
385 cerr << e.get_error_message() << endl;
386 if (report_errors)
387 return EXIT_FAILURE;
388 continue; // Goto the next URL or exit the loop.
389 }
390 }
391 }
392 else {
393 HTTPConnect http(RCReader::instance());
394
395 // This overrides the value set in the .dodsrc file.
396 if (accept_deflate)
397 http.set_accept_deflate(accept_deflate);
398
399 if (dap_client_major > 2)
400 url->set_xdap_protocol(dap_client_major, dap_client_minor);
401
402 string url_string = argv[i];
403 for (int j = 0; j < times; ++j) {
404 try {
405 HTTPResponse *r = http.fetch_url(url_string);
406 if (verbose) {
407 vector <string> *headers = r->get_headers();
408 copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
409 }
410 if (!read_data(r->get_stream())) {
411 continue;
412 }
413 delete r;
414 r = 0;
415 }
416 catch (Error &e) {
417 cerr << e.get_error_message() << endl;
418 if (report_errors)
419 return EXIT_FAILURE;
420 continue;
421 }
422 }
423 }
424
425 delete url;
426 url = nullptr;
427 }
428 }
429 catch (Error &e) {
430 delete url;
431 if (e.get_error_code() == malformed_expr) {
432 cerr << e.get_error_message() << endl;
433 usage(argv[0]);
434 }
435 else {
436 cerr << e.get_error_message() << endl;
437
438 }
439
440 cerr << "Exiting." << endl;
441 return EXIT_FAILURE;
442 }
443 catch (exception &e) {
444 delete url;
445 cerr << "C++ library exception: " << e.what() << endl;
446 cerr << "Exiting." << endl;
447 return EXIT_FAILURE;
448 }
449
450 return EXIT_SUCCESS;
451}
std::string get_protocol()
Definition D4Connect.h:99
void set_accept_deflate(bool deflate)
Definition D4Connect.cc:483
void set_xdap_protocol(int major, int minor)
Definition D4Connect.cc:493
std::string get_version()
Definition D4Connect.h:94
Holds a sequence.
Definition D4Sequence.h:134
D4Group * root()
Definition DMR.cc:296
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition DMR.cc:386
A class for error processing.
Definition Error.h:94
Encapsulate a response read from stdin.
top level DAP object to house generic methods