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 <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 verbose = false;
212 bool accept_deflate = false;
213 bool print_rows = false;
214 bool mime_headers = true;
215 bool report_errors = false;
216 int times = 1;
217 int dap_client_major = 4;
218 int dap_client_minor = 0;
219 string expr;
220 bool compute_size = false;
221
222#ifdef WIN32
223 _setmode(_fileno(stdout), _O_BINARY);
224#endif
225
226 while ((option_char = getopt(argc, argv, "dDvVrm:Mzsc:S")) != -1) {
227 switch (option_char) {
228 case 'd':
229 get_dmr = true;
230 break;
231 case 'D':
232 get_dap4_data = true;
233 break;
234 case 'v':
235 verbose = true;
236 break;
237 case 'V':
238 cerr << "getdap4 version: " << version << endl;
239 exit(0);
240 case 'S':
241 compute_size = true;
242 break;
243 case 'r':
244 report_errors = true;
245 break;
246 case 'm':
247 times = atoi(optarg);
248 break;
249 case 'z':
250 accept_deflate = true;
251 break;
252 case 's':
253 print_rows = true;
254 break;
255 case 'M':
256 mime_headers = false;
257 break;
258 case 'c':
259 expr = optarg;
260 break;
261 case 'h':
262 case '?':
263 default:
264 usage(argv[0]);
265 exit(1);
266 }
267 }
268
269 D4Connect *url = nullptr;
270 try {
271 // If after processing all the command line options there is nothing
272 // left (no URL or file) assume that we should read from stdin.
273 for (int i = optind; i < argc; ++i) {
274 if (verbose)
275 cerr << "Fetching: " << argv[i] << endl;
276
277 string name = argv[i];
278 url = new D4Connect(name);
279
280 // This overrides the value set in the .dodsrc file.
281 if (accept_deflate)
282 url->set_accept_deflate(accept_deflate);
283
284 if (dap_client_major > 2)
285 url->set_xdap_protocol(dap_client_major, dap_client_minor);
286
287 if (url->is_local()) {
288 if (verbose)
289 cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
290
291 try {
292 D4BaseTypeFactory factory;
293 DMR dmr(&factory);
294
295 if (strcmp(argv[i], "-") == 0) {
296 StdinResponse r(cin);
297
298 if (!r.get_cpp_stream())
299 throw Error("Could not open standard input.");
300
301 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
302 }
303 else {
304 fstream f(argv[i], std::ios_base::in);
305 if (!f.is_open() || f.bad() || f.eof())
306 throw Error((string) "Could not open: " + argv[i]);
307
308 Response r(&f, 0);
309
310 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
311 }
312
313 if (verbose)
314 cerr << "DAP version: " << url->get_protocol().c_str() << " Server version: "
315 << url->get_version().c_str() << endl;
316
317 // Always write the DMR
318 XMLWriter xml;
319 dmr.print_dap4(xml);
320 cout << xml.get_doc() << endl;
321
322 if (get_dap4_data)
323 print_data(dmr, print_rows);
324 }
325 catch (Error &e) {
326 cerr << "Error: " << e.get_error_message() << endl;
327 delete url;
328 url = nullptr;
329 if (report_errors)
330 return EXIT_FAILURE;
331 }
332 }
333 else if (get_dmr) {
334 for (int j = 0; j < times; ++j) {
335 D4BaseTypeFactory factory;
336 DMR dmr(&factory);
337 try {
338 url->request_dmr(dmr, expr);
339
340 if (verbose) {
341 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
342 << endl;
343 cout << "DMR:" << endl;
344 }
345
346 XMLWriter xml;
347 dmr.print_dap4(xml);
348 cout << xml.get_doc() << endl;
349 if (compute_size) {
350 cout << "DMR References " << get_size(dmr) << " bytes of data," << endl;
351 }
352 }
353 catch (Error &e) {
354 cerr << e.get_error_message() << endl;
355 if (report_errors)
356 return EXIT_FAILURE;
357 continue; // Goto the next URL or exit the loop.
358 }
359 }
360 }
361 else if (get_dap4_data) {
362 for (int j = 0; j < times; ++j) {
363 D4BaseTypeFactory factory;
364 DMR dmr(&factory);
365 try {
366 url->request_dap4_data(dmr, expr);
367
368 if (verbose) {
369 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
370 << endl;
371 cout << "DMR:" << endl;
372 }
373
374 XMLWriter xml;
375 dmr.print_dap4(xml);
376 cout << xml.get_doc() << endl;
377
378 print_data(dmr, print_rows);
379 }
380 catch (Error &e) {
381 cerr << e.get_error_message() << endl;
382 if (report_errors)
383 return EXIT_FAILURE;
384 continue; // Goto the next URL or exit the loop.
385 }
386 }
387 }
388 else {
389 HTTPConnect http(RCReader::instance());
390
391 // This overrides the value set in the .dodsrc file.
392 if (accept_deflate)
393 http.set_accept_deflate(accept_deflate);
394
395 if (dap_client_major > 2)
396 url->set_xdap_protocol(dap_client_major, dap_client_minor);
397
398 string url_string = argv[i];
399 for (int j = 0; j < times; ++j) {
400 try {
401 HTTPResponse *r = http.fetch_url(url_string);
402 if (verbose) {
403 vector <string> *headers = r->get_headers();
404 copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
405 }
406 if (!read_data(r->get_stream())) {
407 continue;
408 }
409 delete r;
410 r = 0;
411 }
412 catch (Error &e) {
413 cerr << e.get_error_message() << endl;
414 if (report_errors)
415 return EXIT_FAILURE;
416 continue;
417 }
418 }
419 }
420
421 delete url;
422 url = nullptr;
423 }
424 }
425 catch (Error &e) {
426 delete url;
427 if (e.get_error_code() == malformed_expr) {
428 cerr << e.get_error_message() << endl;
429 usage(argv[0]);
430 }
431 else {
432 cerr << e.get_error_message() << endl;
433
434 }
435
436 cerr << "Exiting." << endl;
437 return EXIT_FAILURE;
438 }
439 catch (exception &e) {
440 delete url;
441 cerr << "C++ library exception: " << e.what() << endl;
442 cerr << "Exiting." << endl;
443 return EXIT_FAILURE;
444 }
445
446 return EXIT_SUCCESS;
447}
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:249
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition DMR.cc:339
A class for error processing.
Definition Error.h:94
Encapsulate a response read from stdin.
top level DAP object to house generic methods
Definition AISConnect.cc:30