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 
61 using namespace std;
62 using namespace libdap ;
63 
64 const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
65 #if 0
66 extern int libdap::dods_keep_temps; // defined in HTTPResponse.h
67 extern int libdap::www_trace;
68 #endif
69 static 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
116 bool 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 
132 static 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 
152 static 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 
166 static 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 
187 unsigned 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 
207 unsigned long long get_size(DMR &dmr, bool constrained=false)
208 {
209  return get_size(dmr.root(),constrained);
210 }
211 
212 
213 int 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