libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
getdap4.cc
Go to the documentation of this file.
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 "HTTPResponse.h"
55#include "RCReader.h"
56#include "StdinResponse.h"
57#include "XMLWriter.h"
58
59using namespace std;
60using namespace libdap;
61
62const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
63
64static void usage(const string &) {
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 if (!fp) {
109 fprintf(stderr, "getdap4: Whoa!!! Null stream pointer.\n");
110 return false;
111 }
112 // Changed from a loop that used getc() to one that uses fread(). getc()
113 // worked fine for transfers of text information, but *not* for binary
114 // transfers. fread() will handle both.
115 char c = 0;
116 while (fp && !feof(fp) && fread(&c, 1, 1, fp))
117 printf("%c", c); // stick with stdio
118
119 return true;
120}
121
122static void read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data,
123 bool get_dmr) {
124 if (mime_headers) {
125 if (get_dap4_data)
126 url->read_data(dmr, r);
127 else if (get_dmr)
128 url->read_dmr(dmr, r);
129 else
130 throw Error("Only supports Data or DMR responses");
131 } else {
132 if (get_dap4_data)
133 url->read_data_no_mime(dmr, r);
134 else if (get_dmr)
135 url->read_dmr_no_mime(dmr, r);
136 else
137 throw Error("Only supports Data or DMR responses");
138 }
139}
140
141static void print_group_data(D4Group *g, bool print_rows = false) {
142 for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
143 if (print_rows && (*i)->type() == dods_sequence_c)
144 dynamic_cast<D4Sequence &>(**i).print_val_by_rows(cout);
145 else
146 (*i)->print_val(cout);
147 }
148
149 for (D4Group::groupsIter gi = g->grp_begin(), ge = g->grp_end(); gi != ge; ++gi) {
150 print_group_data(*gi, print_rows);
151 }
152}
153
154static void print_data(DMR &dmr, bool print_rows = false) {
155 cout << "The data:" << endl;
156
157 D4Group *g = dmr.root();
158
159 print_group_data(g, print_rows);
160
161 cout << endl << flush;
162}
163
174unsigned long long get_size(D4Group *grp, bool constrained = false) {
175 unsigned long long w = 0;
176
177 for (auto var_itr = grp->var_begin(); var_itr != grp->var_end(); var_itr++) {
178 if (constrained) {
179 if ((*var_itr)->send_p())
180 w += (*var_itr)->width(constrained);
181 } else {
182 w += (*var_itr)->width(constrained);
183 }
184 }
185 for (auto grp_itr = grp->grp_begin(); grp_itr != grp->grp_end(); grp_itr++) {
186 w += get_size(*grp_itr, constrained);
187 }
188
189 return w;
190}
191
192unsigned long long get_size(DMR &dmr, bool constrained = false) { return get_size(dmr.root(), constrained); }
193
194int main(int argc, char *argv[]) {
195 int option_char;
196
197 bool get_dmr = false;
198 bool get_dap4_data = false;
199 bool verbose = false;
200 bool accept_deflate = false;
201 bool print_rows = false;
202 bool mime_headers = true;
203 bool report_errors = false;
204 int times = 1;
205 int dap_client_major = 4;
206 int dap_client_minor = 0;
207 string expr;
208 bool compute_size = false;
209
210#ifdef WIN32
211 _setmode(_fileno(stdout), _O_BINARY);
212#endif
213
214 while ((option_char = getopt(argc, argv, "dDvVrm:Mzsc:S")) != -1) {
215 switch (option_char) {
216 case 'd':
217 get_dmr = true;
218 break;
219 case 'D':
220 get_dap4_data = true;
221 break;
222 case 'v':
223 verbose = true;
224 break;
225 case 'V':
226 cerr << "getdap4 version: " << version << endl;
227 exit(0);
228 case 'S':
229 compute_size = true;
230 break;
231 case 'r':
232 report_errors = true;
233 break;
234 case 'm':
235 times = atoi(optarg);
236 break;
237 case 'z':
238 accept_deflate = true;
239 break;
240 case 's':
241 print_rows = true;
242 break;
243 case 'M':
244 mime_headers = false;
245 break;
246 case 'c':
247 expr = optarg;
248 break;
249 case 'h':
250 case '?':
251 default:
252 usage(argv[0]);
253 exit(1);
254 }
255 }
256
257 D4Connect *url = nullptr;
258 try {
259 // If after processing all the command line options there is nothing
260 // left (no URL or file) assume that we should read from stdin.
261 for (int i = optind; i < argc; ++i) {
262 if (verbose)
263 cerr << "Fetching: " << argv[i] << endl;
264
265 string name = argv[i];
266 url = new D4Connect(name);
267
268 // This overrides the value set in the .dodsrc file.
269 if (accept_deflate)
270 url->set_accept_deflate(accept_deflate);
271
272 if (dap_client_major > 2)
273 url->set_xdap_protocol(dap_client_major, dap_client_minor);
274
275 if (url->is_local()) {
276 if (verbose)
277 cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
278
279 try {
280 D4BaseTypeFactory factory;
281 DMR dmr(&factory);
282
283 if (strcmp(argv[i], "-") == 0) {
284 StdinResponse r(cin);
285
286 if (!r.get_cpp_stream())
287 throw Error("Could not open standard input.");
288
289 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
290 } else {
291 fstream f(argv[i], std::ios_base::in);
292 if (!f.is_open() || f.bad() || f.eof())
293 throw Error((string) "Could not open: " + argv[i]);
294
295 Response r(&f, 0);
296
297 read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
298 }
299
300 if (verbose)
301 cerr << "DAP version: " << url->get_protocol().c_str()
302 << " Server version: " << url->get_version().c_str() << endl;
303
304 // Always write the DMR
305 XMLWriter xml;
306 dmr.print_dap4(xml);
307 cout << xml.get_doc() << endl;
308
309 if (get_dap4_data)
310 print_data(dmr, print_rows);
311 } catch (Error &e) {
312 cerr << "Error: " << e.get_error_message() << endl;
313 delete url;
314 url = nullptr;
315 if (report_errors)
316 return EXIT_FAILURE;
317 }
318 } else if (get_dmr) {
319 for (int j = 0; j < times; ++j) {
320 D4BaseTypeFactory factory;
321 DMR dmr(&factory);
322 try {
323 url->request_dmr(dmr, expr);
324
325 if (verbose) {
326 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
327 << endl;
328 cout << "DMR:" << endl;
329 }
330
331 XMLWriter xml;
332 dmr.print_dap4(xml);
333 cout << xml.get_doc() << endl;
334 if (compute_size) {
335 cout << "DMR References " << get_size(dmr) << " bytes of data," << endl;
336 }
337 } catch (Error &e) {
338 cerr << e.get_error_message() << endl;
339 if (report_errors)
340 return EXIT_FAILURE;
341 continue; // Goto the next URL or exit the loop.
342 }
343 }
344 } else if (get_dap4_data) {
345 for (int j = 0; j < times; ++j) {
346 D4BaseTypeFactory factory;
347 DMR dmr(&factory);
348 try {
349 url->request_dap4_data(dmr, expr);
350
351 if (verbose) {
352 cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version()
353 << endl;
354 cout << "DMR:" << endl;
355 }
356
357 XMLWriter xml;
358 dmr.print_dap4(xml);
359 cout << xml.get_doc() << endl;
360
361 print_data(dmr, print_rows);
362 } catch (Error &e) {
363 cerr << e.get_error_message() << endl;
364 if (report_errors)
365 return EXIT_FAILURE;
366 continue; // Goto the next URL or exit the loop.
367 }
368 }
369 } else {
371
372 // This overrides the value set in the .dodsrc file.
373 if (accept_deflate)
374 http.set_accept_deflate(accept_deflate);
375
376 if (dap_client_major > 2)
377 url->set_xdap_protocol(dap_client_major, dap_client_minor);
378
379 string url_string = argv[i];
380 for (int j = 0; j < times; ++j) {
381 try {
382 HTTPResponse *r = http.fetch_url(url_string);
383 if (verbose) {
384 vector<string> &headers = r->get_headers();
385 copy(headers.begin(), headers.end(), ostream_iterator<string>(cout, "\n"));
386 }
387 if (!read_data(r->get_stream())) {
388 continue;
389 }
390 delete r;
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}
#define malformed_expr
(400)
Definition Error.h:66
std::vector< BaseType * >::iterator Vars_iter
Definition Constructor.h:60
Vars_iter var_begin()
bool is_local() const
Definition D4Connect.h:69
virtual void read_dmr_no_mime(DMR &dmr, Response &rs)
Definition D4Connect.cc:416
std::string get_protocol()
Definition D4Connect.h:97
virtual void read_data_no_mime(DMR &data, Response &rs)
Definition D4Connect.cc:440
virtual void request_dap4_data(DMR &dmr, const std::string expr="")
Definition D4Connect.cc:345
virtual void read_data(DMR &data, Response &rs)
Definition D4Connect.cc:432
void set_accept_deflate(bool deflate)
Definition D4Connect.cc:469
virtual void request_dmr(DMR &dmr, const std::string expr="")
Definition D4Connect.cc:305
virtual void read_dmr(DMR &dmr, Response &rs)
Definition D4Connect.cc:408
void set_xdap_protocol(int major, int minor)
Definition D4Connect.cc:479
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
vector< D4Group * >::iterator groupsIter
Definition D4Group.h:68
Holds a sequence.
Definition D4Sequence.h:131
virtual void print_val_by_rows(ostream &out, string space="", bool print_decl_p=true, bool print_row_numbers=true)
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
const char * what() const noexcept override
The pointer is valid only for the lifetime of the Error instance. jhrg 9/22/20.
Definition Error.h:152
ErrorCode get_error_code() const
Definition Error.cc:189
std::string get_error_message() const
Definition Error.cc:212
void set_accept_deflate(bool deflate)
HTTPResponse * fetch_url(const std::string &url)
virtual std::vector< std::string > & get_headers()
static RCReader * instance()
Definition RCReader.cc:427
virtual FILE * get_stream() const
Definition Response.h:103
Encapsulate a response read from stdin.
virtual std::istream * get_cpp_stream() const
const char * get_doc()
Definition XMLWriter.cc:104
#define CVER
Definition config.h:32
#define DAP_PROTOCOL_VERSION
Definition config.h:41
#define DVR
Definition config.h:80
unsigned long long get_size(D4Group *grp, bool constrained=false)
Definition getdap4.cc:174
int main(int argc, char *argv[])
Definition getdap4.cc:194
bool read_data(FILE *fp)
Definition getdap4.cc:107
const char * version
Definition getdap.cc:65
top level DAP object to house generic methods
Definition AISConnect.cc:30
@ dods_sequence_c
Definition Type.h:108
const string usage
Definition DODSFilter.cc:89