bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
get_html_form.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// Copyright (c) 2006 OPeNDAP, Inc.
5// Author: James Gallagher <jgallagher@opendap.org>
6//
7// This is free software; you can redistribute it and/or modify it under the
8// terms of the GNU Lesser General Public License as published by the Free
9// Software Foundation; either version 2.1 of the License, or (at your
10// option) any later version.
11//
12// This is distributed in the hope that it will be useful, but WITHOUT ANY
13// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15// more details.
16//
17// You should have received a copy of the GNU Lesser General Public
18// License along with this library; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20//
21// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
22
23// This file holds the interface for the 'get data as ascii' function of the
24// OPeNDAP/HAO data server. This function is called by the BES when it loads
25// this as a module. The functions in the file ascii_val.cc also use this, so
26// the same basic processing software can be used both by Hyrax and tie older
27// Server3.
28
29#include <stdio.h>
30#include <sys/types.h>
31#include <unistd.h>
32
33#include <iostream>
34#include <sstream>
35
36#include <libdap/DataDDS.h>
37#include <libdap/escaping.h>
38
39#include "get_html_form.h"
40#include "WWWOutput.h"
41#include "WWWOutputFactory.h"
42
43#include "WWWByte.h"
44#include "WWWInt16.h"
45#include "WWWUInt16.h"
46#include "WWWInt32.h"
47#include "WWWUInt32.h"
48#include "WWWFloat32.h"
49#include "WWWFloat64.h"
50#include "WWWStr.h"
51#include "WWWUrl.h"
52#include "WWWArray.h"
53#include "WWWStructure.h"
54#include "WWWSequence.h"
55#include "WWWGrid.h"
56
57namespace dap_html_form {
58
59#include "javascript.h" // Try to hide this stuff...
60
61// A better way to do this would have been to make WWWStructure, ..., inherit
62// from both Structure and WWWOutput. But I didn't... jhrg 8/29/05
63WWWOutput *wo = 0;
64
70BaseType *basetype_to_wwwtype(BaseType * bt)
71{
72 switch (bt->type()) {
73 case dods_byte_c:
74 return new WWWByte(dynamic_cast < Byte * >(bt));
75 case dods_int16_c:
76 return new WWWInt16(dynamic_cast < Int16 * >(bt));
77 case dods_uint16_c:
78 return new WWWUInt16(dynamic_cast < UInt16 * >(bt));
79 case dods_int32_c:
80 return new WWWInt32(dynamic_cast < Int32 * >(bt));
81 case dods_uint32_c:
82 return new WWWUInt32(dynamic_cast < UInt32 * >(bt));
83 case dods_float32_c:
84 return new WWWFloat32(dynamic_cast < Float32 * >(bt));
85 case dods_float64_c:
86 return new WWWFloat64(dynamic_cast < Float64 * >(bt));
87 case dods_str_c:
88 return new WWWStr(dynamic_cast < Str * >(bt));
89 case dods_url_c:
90 return new WWWUrl(dynamic_cast < Url * >(bt));
91 case dods_array_c:
92 return new WWWArray(dynamic_cast < Array * >(bt));
93 case dods_structure_c:
94 return new WWWStructure(dynamic_cast < Structure * >(bt));
95 case dods_sequence_c:
96 return new WWWSequence(dynamic_cast < Sequence * >(bt));
97 case dods_grid_c:
98 return new WWWGrid(dynamic_cast < Grid * >(bt));
99 default:
100 throw InternalErr(__FILE__, __LINE__, "Unknown type.");
101 }
102}
103
110DDS *dds_to_www_dds(DDS * dds)
111{
112#if 0
113 // Using the factory class has no effect because it does not control
114 // how a class like Structure or Grid builds child instances, so we have
115 // to use the basetype_to_wwwtype() function.
116 WWWOutputFactory wwwfactory;
117 dds->set_factory(&wwwfactory);
118#endif
119 // Use the copy constructor to copy all the various private fields in DDS
120 // including the attribute table for global attributes
121 DDS *wwwdds = new DDS(*dds);
122
123 // Because the DDS copy constructor copies the variables, we now, erase
124 // them and...
125 wwwdds->del_var(wwwdds->var_begin(), wwwdds->var_end());
126
127 // Build copies of the variables using the WWW* types and manually add
128 // their attribute tables.
129 DDS::Vars_iter i = dds->var_begin();
130 while (i != dds->var_end()) {
131 BaseType *abt = basetype_to_wwwtype(*i);
132 abt->set_attr_table((*i)->get_attr_table());
133#if 0
134 cerr << "dds attr: "; (*i)->get_attr_table().print(cerr); cerr << endl;
135 cerr << "abt attr: "; abt->get_attr_table().print(cerr); cerr << endl;
136#endif
137 wwwdds->add_var(abt);
138 // add_var makes a copy of the base type passed to it, so delete it
139 // here
140 delete abt;
141 i++;
142 }
143
144#if 0
145 // Should the following use WWWOutputFactory instead of the source DDS'
146 // factory class?
147 DDS *wwwdds = new DDS(dds->get_factory(), dds->get_dataset_name());
148
149 wwwdds->set_attr_table(dds->get_attr_table);
150
151 DDS::Vars_iter i = dds->var_begin();
152 while (i != dds->var_end()) {
153 BaseType *abt = basetype_to_wwwtype(*i);
154 wwwdds->add_var(abt);
155 // add_var makes a copy of the base type passed to it, so delete it
156 // here
157 delete abt;
158 i++;
159 }
160#endif
161 return wwwdds;
162}
163
164// This hack is needed because we have moved the #define of FILE_METHODS to
165// the libdap header files until we can remove those methods from the library.
166#undef FILE_METHODS
167
168#ifdef FILE_METHODS
188void write_html_form_interface(FILE * dest, DDS * dds,
189 const string & url, bool html_header,
190 const string & admin_name,
191 const string & help_location)
192{
193 wo = new WWWOutput(dest);
194
195 if (html_header)
196 wo->write_html_header();
197
198 ostringstream oss;
199 oss <<
200 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n"
201 << "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n" <<
202 "<html><head><title>OPeNDAP Server Dataset Query Form</title>\n"
203 << "<base href=\"" << help_location << "\">\n" <<
204 "<script type=\"text/javascript\">\n"
205 // Javascript code here
206 << java_code << "\n"
207 << "DODS_URL = new dods_url(\"" << url << "\");\n"
208 << "</script>\n"
209
210 << "<style id=\"antiClickjack\">body{display:none !important;}</style>\n" //cross frame fix.
211 << "<script type=\"text/javascript\">\n"
212 << " if (self === top) {\n"
213 << " var antiClickjack = document.getElementById(\"antiClickjack\");\n"
214 << " antiClickjack.parentNode.removeChild(antiClickjack);\n"
215 << " } else {\n"
216 << " top.location = self.location;\n"
217 << " }\n"
218 << "</script>\n"
219
220 << "</head>\n"
221 << "<body>\n"
222 <<
223 "<p><h2 align='center'>OPeNDAP Server Dataset Access Form</h2>\n"
224 << "<hr>\n" << "<form action=\"\">\n" << "<table>\n";
225 fprintf(dest, "%s", oss.str().c_str());
226
227 wo->write_disposition(url);
228
229 fprintf(dest, "<tr><td><td><hr>\n\n");
230
231 wo->write_global_attributes(dds->get_attr_table());
232
233 fprintf(dest, "<tr><td><td><hr>\n\n");
234
235 wo->write_variable_entries(*dds);
236
237 oss.str("");
238 oss << "</table></form>\n\n" << "<hr>\n\n";
239 oss << "<address>Send questions or comments to: <a href=\"mailto:"
240 << admin_name << "\">" << admin_name << "</a></address>" << "<p>\n\
241 <a href=\"http://validator.w3.org/check?uri=referer\"><img\n\
242 src=\"http://www.w3.org/Icons/valid-html40\"\n\
243 alt=\"Valid HTML 4.0 Transitional\" height=\"31\" width=\"88\">\n\
244 </a></p>\n" << "</body></html>\n";
245
246 fprintf(dest, "%s", oss.str().c_str());
247
248}
249#endif
269void write_html_form_interface(ostream &strm, DDS * dds, const string & url, bool html_header,
270 bool netcdf3_file_response, bool netcdf4_file_response, const string & admin_name,
271 const string & help_location)
272{
273 wo = new WWWOutput(strm);
274
275 if (html_header)
276 wo->write_html_header();
277
278 strm <<
279 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n"
280 << "\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n" <<
281 "<html><head><title>OPeNDAP Server Dataset Query Form</title>\n"
282 << "<base href=\"" << help_location << "\">\n" <<
283 "<script type=\"text/javascript\">\n"
284 // Javascript code here
285 << java_code << "\n"
286 << "DODS_URL = new dods_url(\"" << url << "\");\n"
287 << "</script>\n"
288
289 << "<style id=\"antiClickjack\">body{display:none !important;}</style>\n" //cross frame fix.
290 << "<script type=\"text/javascript\">\n"
291 << " if (self === top) {\n"
292 << " var antiClickjack = document.getElementById(\"antiClickjack\");\n"
293 << " antiClickjack.parentNode.removeChild(antiClickjack);\n"
294 << " } else {\n"
295 << " top.location = self.location;\n"
296 << " }\n"
297 << "</script>\n"
298
299 << "</head>\n"
300 << "<body>\n"
301 <<
302 "<p><h2 align='center'>OPeNDAP Server Dataset Access Form</h2>\n"
303 << "<hr>\n" << "<form action=\"\">\n" << "<table>\n";
304
305 wo->write_disposition(url, netcdf3_file_response, netcdf4_file_response);
306
307 strm << "<tr><td><td><hr>\n\n" ;
308
309 wo->write_global_attributes(dds->get_attr_table());
310
311 strm << "<tr><td><td><hr>\n\n" ;
312
313 wo->write_variable_entries(*dds);
314
315 strm << "</table></form>\n\n" << "<hr>\n\n";
316 strm << "<address>Send questions or comments to: <a href=\"mailto:"
317 << admin_name << "\">" << admin_name << "</a></address>" << "<p>\n\
318 <a href=\"http://validator.w3.org/check?uri=referer\"><img\n\
319 src=\"http://www.w3.org/Icons/valid-html40\"\n\
320 alt=\"Valid HTML 4.0 Transitional\" height=\"31\" width=\"88\">\n\
321 </a></p>\n" << "</body></html>\n";
322}
323
324const string allowable =
325 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
326
327// This function adds some text to the variable name so that conflicts with
328// JavaScript's reserved words and other conflicts are avoided (or
329// minimized...) 7/13/2001 jhrg
330//
331// I've modified this so that it no longer include the PID. Not sure why that
332// was included... However, removing it will make using the HTML form in tests
333// easier. jhrg 11/28/06
334string name_for_js_code(const string & dods_name)
335{
336 return string("org_opendap_") +
337 esc2underscore(id2www(dods_name, allowable));
338}
339
345string
346get_fqn(BaseType *var)
347{
348 // I made this a local static object to avoid the repeated cost of creation
349 // and also the issues with global static objects in dynamically-loaded
350 // code.
351 static const string dot = ".";
352
353 // Testing !get_parent() means that the function returns the top most name.
354 // If we tested !var instead it would return "" and the FQN would have a
355 // leading dot. The test for !var is here as cheap insurance; it should
356 // never happen.
357 if (!var)
358 return string("");
359 else if (!var->get_parent())
360 return var->name();
361 else
362 return get_fqn(var->get_parent()) + dot + var->name();
363}
364
365string fancy_typename(BaseType * v)
366{
367 switch (v->type()) {
368 case dods_byte_c:
369 return "Byte";
370 case dods_int16_c:
371 return "16 bit Integer";
372 case dods_uint16_c:
373 return "16 bit Unsigned integer";
374 case dods_int32_c:
375 return "32 bit Integer";
376 case dods_uint32_c:
377 return "32 bit Unsigned integer";
378 case dods_float32_c:
379 return "32 bit Real";
380 case dods_float64_c:
381 return "64 bit Real";
382 case dods_str_c:
383 return "string";
384 case dods_url_c:
385 return "URL";
386 case dods_array_c:{
387 ostringstream type;
388 Array *a = (Array *) v;
389 type << "Array of " << fancy_typename(a->var()) << "s ";
390 for (Array::Dim_iter p = a->dim_begin(); p != a->dim_end();
391 ++p)
392 type << "[" << a->dimension_name(p) << " = 0.." << a->
393 dimension_size(p, false) - 1 << "]";
394 return type.str();
395 }
396 case dods_structure_c:
397 return "Structure";
398 case dods_sequence_c:
399 return "Sequence";
400 case dods_grid_c:{
401 ostringstream type;
402 Grid &g = dynamic_cast<Grid&>(*v);
403 type << "Grid of " << fancy_typename(g.get_array());
404#if 0
405 << "s ";
406 for (Grid::Map_iter p = g.map_begin(); p != g.map_end(); ++p) {
407 Array &a = dynamic_cast<Array&>(**p);
408 type << "[" << a.dimension_name(a.dim_begin()) << " = 0.." \
409 << a.dimension_size(a.dim_begin(), false) - 1 << "]";
410 }
411#endif
412 return type.str();
413 }
414#if 0
415 return "Grid";
416#endif
417 default:
418 return "Unknown";
419 }
420}
421
428void
429write_simple_variable(FILE * os, BaseType *var)
430// const string & name, const string & type)
431{
432 ostringstream ss;
433 write_simple_variable( ss, var); //name, type ) ;
434
435 // Now write that string to os
436 fprintf(os, "%s", ss.str().c_str());
437}
438
445void
446write_simple_variable(ostream &strm, BaseType *var)
447// const string & name, const string & type)
448{
449 const string fqn = get_fqn(var);
450
451 strm << "<script type=\"text/javascript\">\n"
452 << name_for_js_code(fqn) << " = new dods_var(\""
453 << id2www_ce(fqn)
454 << "\", \"" << name_for_js_code(fqn) << "\", 0);\n" <<
455 "DODS_URL.add_dods_var(" << name_for_js_code(fqn) << ");\n"
456 << "</script>\n";
457
458 strm << "<b>"
459 << "<input type=\"checkbox\" name=\"get_" << name_for_js_code(fqn)
460 << "\"\n" << "onclick=\"" << name_for_js_code(fqn)
461 << ".handle_projection_change(get_" << name_for_js_code(fqn)
462 << ") \" onfocus=\"describe_projection()\">\n" << "<font size=\"+1\">"
463 << var->name() << "</font>" << ": "
464 << fancy_typename(var) << "</b><br>\n\n";
465
466 strm << var->name() << " <select name=\"" << name_for_js_code(fqn)
467 << "_operator\"" << " onfocus=\"describe_operator()\""
468 << " onchange=\"DODS_URL.update_url()\">\n"
469 << "<option value=\"=\" selected>=\n"
470 << "<option value=\"!=\">!=\n" << "<option value=\"<\"><\n"
471 << "<option value=\"<=\"><=\n" << "<option value=\">\">>\n"
472 << "<option value=\">=\">>=\n" << "<option value=\"-\">--\n"
473 << "</select>\n";
474
475 strm << "<input type=\"text\" name=\"" << name_for_js_code(fqn)
476 << "_selection"
477 << "\" size=12 onFocus=\"describe_selection()\" "
478 << "onChange=\"DODS_URL.update_url()\">\n";
479
480 strm << "<br>\n\n";
481}
482#if 0
483void
484write_simple_var_attributes(FILE * os, BaseType *var)
485{
486 ostringstream ss;
487 write_simple_var_attributes(ss, var);
488
489 // Now write that string to os
490 fprintf(os, "%s", ss.str().c_str());
491}
492
493void
494write_simple_var_attributes(ostream &os, int rows, int cols, BaseType *btp)
495{
496 AttrTable &attr = btp->get_attr_table();
497
498 // Don't write anything if there are no attributes.
499 if (attr.get_size() == 0) {
500 return;
501 }
502
503 os << "<textarea name=\"" << btp->name()
504 << "_attr\" rows=\"" << rows
505 << "\" cols=\"" << cols << "\">\n" ;
506 write_attributes(os, attr, "");
507 os << "</textarea>\n\n" ;
508}
509
510void
511write_attributes(ostream &os, AttrTable &attr, const string &prefix)
512{
513 for (AttrTable::Attr_iter a = attr.attr_begin(); a != attr.attr_end(); ++a) {
514 if (attr.is_container(a))
515 write_attributes(os, attr.get_attr_table(a), (prefix == "") ? attr.get_name(a) : prefix + string(".") + attr.get_name(a));
516 else {
517 if (prefix != "")
518 os << prefix << "." << attr.get_name(a) << ": ";
519 else
520 os << attr.get_name(a) << ": ";
521
522 int num_attr = attr.get_attr_num(a) - 1;
523 for (int i = 0; i < num_attr; ++i) {
524 os << attr.get_attr(a, i) << ", ";
525 }
526 os << attr.get_attr(a, num_attr) << "\n";
527 }
528 }
529}
530#endif
531} // namespace dap_html_form