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