libdap++  Updated for version 3.14.0
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 <io.h>
40 #include <fcntl.h>
41 #endif
42 
43 #include <cstring>
44 #include <string>
45 #include <sstream>
46 
47 #include "GetOpt.h"
48 
49 #include "DMR.h"
50 #include "XMLWriter.h"
51 #include "D4BaseTypeFactory.h"
52 #include "D4Group.h"
53 #include "D4Sequence.h"
54 #include "D4Connect.h"
55 #include "StdinResponse.h"
56 #include "HTTPConnect.h"
57 #include "RCReader.h"
58 
59 using namespace std;
60 using namespace libdap ;
61 
62 const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
63 #if 0
64 extern int libdap::dods_keep_temps; // defined in HTTPResponse.h
65 extern int libdap::www_trace;
66 #endif
67 static void usage(const string &name)
68 {
69  cerr << "Usage: " << name << endl;
70  cerr << " [dD vVikmzstM][-c <expr>][-m <num>] <url> [<url> ...] | <file> [<file> ...]" << endl;
71  cerr << endl;
72  cerr << "In the first form of the command, dereference the URL and" << endl;
73  cerr << "perform the requested operations. This includes routing" << endl;
74  cerr << "the returned information through the DAP processing" << endl;
75  cerr << "library (parsing the returned objects, et c.). If none" << endl;
76  cerr << "of a, d, or D are used with a URL, then the DAP library" << endl;
77  cerr << "routines are NOT used and the URLs contents are dumped" << endl;
78  cerr << "to standard output." << endl;
79  cerr << endl;
80  cerr << "In the second form of the command, assume the files are" << endl;
81  cerr << "DataDDS objects (stored in files or read from pipes)" << endl;
82  cerr << "and process them as if -D were given. In this case the" << endl;
83  cerr << "information *must* contain valid MIME header in order" << endl;
84  cerr << "to be processed." << endl;
85  cerr << endl;
86  cerr << "Options:" << endl;
87  cerr << " d: For each URL, get the (DAP4) DMR object. Does not get data." << endl;
88  cerr << " D: For each URL, get the DAP4 Data response." << endl;
89  cerr << endl;
90  cerr << " v: Verbose output." << endl;
91  cerr << " V: Version of this client; see 'i' for server version." << endl;
92  cerr << " i: For each URL, get the server version." << endl;
93  cerr << " k: Keep temporary files created by libdap." << endl;
94  cerr << " m: Request the same URL <num> times." << endl;
95  cerr << " z: Ask the server to compress data." << endl;
96  cerr << " s: Print Sequences using numbered rows." << endl;
97  cerr << " t: Trace www accesses." << endl;
98  cerr << " M: Assume data read from a file has no MIME headers; use only with files" << endl;
99  cerr << endl;
100  cerr << " c: <expr> is a constraint expression. Used with -d/D" << endl;
101  cerr << " NB: You can use a `?' for the CE also." << endl;
102 }
103 
104 #if 1
105 // Used for raw http access/transfer
106 bool read_data(FILE * fp)
107 {
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;
116  while (fp && !feof(fp) && fread(&c, 1, 1, fp))
117  printf("%c", c); // stick with stdio
118 
119  return true;
120 }
121 #endif
122 
123 static void read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data, bool get_dmr)
124 {
125  if (mime_headers) {
126  if (get_dap4_data)
127  url->read_data(dmr, r);
128  else if (get_dmr)
129  url->read_dmr(dmr, r);
130  else
131  throw Error("Only supports Data or DMR responses");
132  }
133  else {
134  if (get_dap4_data)
135  url->read_data_no_mime(dmr, r);
136  else if (get_dmr)
137  url->read_dmr_no_mime(dmr, r);
138  else
139  throw Error("Only supports Data or DMR responses");
140  }
141 }
142 
143 static void print_data(DMR &dmr, bool print_rows = false)
144 {
145  cout << "The data:" << endl;
146 
147  D4Group *g = dmr.root();
148  for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
149  if (print_rows && (*i)->type() == dods_sequence_c)
150  dynamic_cast < D4Sequence * >(*i)->print_val_by_rows(cout);
151  else
152  (*i)->print_val(cout);
153  }
154 
155  cout << endl << flush;
156 }
157 
158 int main(int argc, char *argv[])
159 {
160  GetOpt getopt(argc, argv, "[dDvVikrm:Mzstc:]");
161  int option_char;
162 
163  bool get_dmr = false;
164  bool get_dap4_data = false;
165  bool get_version = false;
166  bool cexpr = false;
167  bool verbose = false;
168  bool multi = false;
169  bool accept_deflate = false;
170  bool print_rows = false;
171  bool mime_headers = true;
172  bool report_errors = false;
173  int times = 1;
174  int dap_client_major = 4;
175  int dap_client_minor = 0;
176  string expr = "";
177 
178 #ifdef WIN32
179  _setmode(_fileno(stdout), _O_BINARY);
180 #endif
181 
182  while ((option_char = getopt()) != -1)
183  switch (option_char) {
184  case 'd':
185  get_dmr = true;
186  break;
187  case 'D':
188  get_dap4_data = true;
189  break;
190  case 'v':
191  verbose = true;
192  break;
193  case 'V':
194  cerr << "getdap4 version: " << version << endl;
195  exit(0);
196  case 'i':
197  get_version = true;
198  break;
199 #if 0
200  case 'k':
201  dods_keep_temps = 1;
202  break; // keep_temp is in Connect.cc
203 #endif
204  case 'r':
205  report_errors = true;
206  break;
207  case 'm':
208  multi = true;
209  times = atoi(getopt.optarg);
210  break;
211  case 'z':
212  accept_deflate = true;
213  break;
214  case 's':
215  print_rows = true;
216  break;
217  case 'M':
218  mime_headers = false;
219  break;
220 #if 0
221  case 't':
222  www_trace = 1;
223  break;
224 #endif
225  case 'c':
226  cexpr = true;
227  expr = getopt.optarg;
228  break;
229  case 'h':
230  case '?':
231  default:
232  usage(argv[0]);
233  exit(1);
234  break;
235  }
236 
237  try {
238  // If after processing all the command line options there is nothing
239  // left (no URL or file) assume that we should read from stdin.
240  for (int i = getopt.optind; i < argc; ++i) {
241  if (verbose)
242  cerr << "Fetching: " << argv[i] << endl;
243 
244  string name = argv[i];
245  D4Connect *url = 0;
246 
247  url = new D4Connect(name);
248 
249  // This overrides the value set in the .dodsrc file.
250  if (accept_deflate)
251  url->set_accept_deflate(accept_deflate);
252 
253  if (dap_client_major > 2)
254  url->set_xdap_protocol(dap_client_major, dap_client_minor);
255 
256  if (url->is_local()) {
257  if (verbose)
258  cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
259 
260  try {
261  D4BaseTypeFactory factory;
262  DMR dmr(&factory);
263 
264  if (strcmp(argv[i], "-") == 0) {
265  StdinResponse r(cin);
266 
267  if (!r.get_cpp_stream())
268  throw Error("Could not open standard input.");
269 
270  read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
271  }
272  else {
273  fstream f(argv[i], std::ios_base::in);
274  if (!f.is_open() || f.bad() || f.eof())
275  throw Error((string)"Could not open: " + argv[i]);
276 
277  Response r(&f, 0);
278 
279  read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
280  }
281 
282  if (verbose)
283  cerr << "DAP version: " << url->get_protocol().c_str() << " Server version: "
284  << url->get_version().c_str() << endl;
285 
286  // Always write the DMR
287  XMLWriter xml;
288  dmr.print_dap4(xml);
289  cout << xml.get_doc() << endl;
290 
291  if (get_dap4_data)
292  print_data(dmr, print_rows);
293  }
294  catch (Error & e) {
295  cerr << "Error: " << e.get_error_message() << endl;
296  delete url; url = 0;
297  }
298  }
299  else if (get_dmr) {
300  for (int j = 0; j < times; ++j) {
301  D4BaseTypeFactory factory;
302  DMR dmr(&factory);
303  try {
304  url->request_dmr(dmr, expr);
305 
306  if (verbose) {
307  cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
308  cout << "DMR:" << endl;
309  }
310 
311  XMLWriter xml;
312  dmr.print_dap4(xml);
313  cout << xml.get_doc() << endl;
314  }
315  catch (Error & e) {
316  cerr << e.get_error_message() << endl;
317  if (report_errors)
318  return EXIT_FAILURE;
319  continue; // Goto the next URL or exit the loop.
320  }
321  }
322  }
323  else if (get_dap4_data) {
324  for (int j = 0; j < times; ++j) {
325  D4BaseTypeFactory factory;
326  DMR dmr(&factory);
327  try {
328  url->request_dap4_data(dmr, expr);
329 
330  if (verbose) {
331  cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
332  cout << "DMR:" << endl;
333  }
334 
335  XMLWriter xml;
336  dmr.print_dap4(xml);
337  cout << xml.get_doc() << endl;
338 
339  print_data(dmr, print_rows);
340  }
341  catch (Error & e) {
342  cerr << e.get_error_message() << endl;
343  continue; // Goto the next URL or exit the loop.
344  }
345  }
346  }
347  else {
348  HTTPConnect http(RCReader::instance());
349 
350  // This overrides the value set in the .dodsrc file.
351  if (accept_deflate)
352  http.set_accept_deflate(accept_deflate);
353 
354  if (dap_client_major > 2)
355  url->set_xdap_protocol(dap_client_major, dap_client_minor);
356 
357  string url_string = argv[i];
358  for (int j = 0; j < times; ++j) {
359  try {
360  HTTPResponse *r = http.fetch_url(url_string);
361  if (verbose) {
362  vector<string> *headers = r->get_headers();
363  copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
364  }
365  if (!read_data(r->get_stream())) {
366  continue;
367  }
368  delete r;
369  r = 0;
370  }
371  catch (Error & e) {
372  cerr << e.get_error_message() << endl;
373  continue;
374  }
375  }
376  }
377 
378 #if 0
379  else if (get_version) {
380  fprintf(stderr, "DAP version: %s, Server version: %s\n",
381  url->request_protocol().c_str(),
382  url->get_version().c_str());
383  }
384 #endif
385 
386  delete url; url = 0;
387  }
388  }
389  catch (Error &e) {
390  cerr << "Error: " << e.get_error_message() << endl;
391  cerr << "exiting" << endl;
392  return 1;
393  }
394  catch (exception &e) {
395  cerr << "C++ library exception: " << e.what() << endl;
396  cerr << "exiting" << endl;
397  return 1;
398  }
399 
400  return 0;
401 }
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: DMR.cc:314
string get_error_message() const
Definition: Error.cc:275
D4Group * root()
Definition: DMR.cc:243
std::vector< BaseType * >::iterator Vars_iter
Definition: Constructor.h:62
std::string get_version()
Definition: D4Connect.h:90
void set_xdap_protocol(int major, int minor)
Definition: D4Connect.cc:1127
HTTPResponse * fetch_url(const string &url)
Definition: HTTPConnect.cc:615
std::string get_protocol()
Definition: D4Connect.h:95
void set_accept_deflate(bool deflate)
Definition: D4Connect.cc:1116
const char * get_doc()
Definition: XMLWriter.cc:105
virtual void request_dmr(DMR &dmr, const std::string expr="")
Definition: D4Connect.cc:286
bool read_data(FILE *fp)
Definition: getdap4.cc:106
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Constructor.cc:624
#define DVR
Definition: config.h:85
int main(int argc, char *argv[])
Definition: getdap4.cc:158
virtual void read_dmr(DMR &dmr, Response &rs)
Definition: D4Connect.cc:1048
void set_accept_deflate(bool defalte)
Definition: HTTPConnect.cc:988
virtual void request_dap4_data(DMR &dmr, const std::string expr="")
Definition: D4Connect.cc:329
virtual void read_dmr_no_mime(DMR &dmr, Response &rs)
Definition: D4Connect.cc:1058
Encapsulate a response read from stdin.
Definition: StdinResponse.h:44
int dods_keep_temps
Definition: HTTPConnect.cc:79
virtual void read_data_no_mime(DMR &data, Response &rs)
Definition: D4Connect.cc:1085
Vars_iter var_begin()
Definition: Constructor.cc:331
Vars_iter var_end()
Definition: Constructor.cc:339
#define CVER
Definition: config.h:37
A class for error processing.
Definition: Error.h:90
#define DAP_PROTOCOL_VERSION
Definition: config.h:46
virtual void read_data(DMR &data, Response &rs)
Definition: D4Connect.cc:1076
virtual std::istream * get_cpp_stream() const
Definition: StdinResponse.h:76
virtual std::vector< std::string > * get_headers() const
Definition: HTTPResponse.h:158
int www_trace
Definition: HTTPConnect.cc:76
void usage(string name)
Definition: getdap.cc:65
virtual FILE * get_stream() const
Definition: Response.h:106
bool is_local() const
Definition: D4Connect.h:67
const char * version
Definition: getdap4.cc:62