44 #ifndef TM_IN_SYS_TIME
50 #include <sys/types.h>
75 #define FILE_DELIMITER '\\'
76 #else // default to unix
77 #define FILE_DELIMITER '/'
81 #define CRLF "\r\n" // Change here, expr-test.cc, in DODSFilter and ResponseBuilder
97 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
134 static const char *days[] =
135 {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
137 static const char *months[] =
138 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
139 "Aug",
"Sep",
"Oct",
"Nov",
"Dec"
143 #define snprintf sprintf_s
156 struct tm *stm = gmtime(&t);
162 snprintf(d, 255,
"%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday],
163 stm->tm_mday, months[stm->tm_mon],
165 stm->tm_hour, stm->tm_min, stm->tm_sec);
170 static const int TimLen = 26;
187 do_version(
const string &script_ver,
const string &dataset_ver)
189 fprintf(stdout,
"HTTP/1.0 200 OK%s",
CRLF) ;
190 fprintf(stdout,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
191 fprintf(stdout,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
193 fprintf(stdout,
"Content-Type: text/plain%s",
CRLF) ;
194 fprintf(stdout,
CRLF) ;
196 fprintf(stdout,
"Core software version: %s%s",
DVR,
CRLF) ;
198 if (script_ver !=
"")
199 fprintf(stdout,
"Server Script Revision: %s%s", script_ver.c_str(),
CRLF) ;
201 if (dataset_ver !=
"")
202 fprintf(stdout,
"Dataset version: %s%s", dataset_ver.c_str(),
CRLF) ;
225 if (time(&TimBin) == (time_t) - 1)
226 strncpy(TimStr,
"time() error ", TimLen-1);
228 char *ctime_value = ctime(&TimBin);
230 strncpy(TimStr,
"Unknown", TimLen-1);
232 strncpy(TimStr, ctime_value, TimLen-1);
233 TimStr[TimLen - 2] =
'\0';
236 strncpy(TimStr, ctime(&TimBin), TimLen-1);
237 TimStr[TimLen - 2] =
'\0';
241 cerr <<
"[" << TimStr <<
"] DAP server error: " << Msgt << endl;
272 string::size_type pound = path.find_last_of(
"#");
275 if (pound != string::npos)
276 new_path = path.substr(pound + 1);
278 new_path = path.substr(delim + 1);
293 static const char *descrip[] =
294 {
"unknown",
"dods_das",
"dods_dds",
"dods_data",
295 "dods_error",
"web_error",
"dap4-ddx",
"dap4-data",
"dap4-error",
296 "dap4-data-ddx",
"dods_ddx"
298 static const char *encoding[] =
299 {
"unknown",
"deflate",
"x-plain",
"gzip",
"binary"
310 if ((value ==
"dods_das") | (value ==
"dods-das"))
312 else if ((value ==
"dods_dds") | (value ==
"dods-dds"))
314 else if ((value ==
"dods_data") | (value ==
"dods-data"))
316 else if ((value ==
"dods_error") | (value ==
"dods-error"))
318 else if ((value ==
"web_error") | (value ==
"web-error"))
320 else if ((value ==
"dap4_ddx") | (value ==
"dap4-ddx"))
322 else if ((value ==
"dap4_data") | (value ==
"dap4-data"))
324 else if ((value ==
"dap4_error") | (value ==
"dap4-error"))
326 else if ((value ==
"dap4_data_ddx") | (value ==
"dap4-data-ddx"))
328 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
342 if ((value ==
"dods_das") | (value ==
"dods-das"))
344 else if ((value ==
"dods_dds") | (value ==
"dods-dds"))
346 else if ((value ==
"dods_data") | (value ==
"dods-data"))
348 else if ((value ==
"dods_error") | (value ==
"dods-error"))
350 else if ((value ==
"web_error") | (value ==
"web-error"))
352 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
354 else if ((value ==
"dap4_ddx") | (value ==
"dap4-ddx"))
356 else if ((value ==
"dap4_data") | (value ==
"dap4-data"))
358 else if ((value ==
"dap4_error") | (value ==
"dap4-error"))
360 else if ((value ==
"dap4_data_ddx") | (value ==
"dap4-data-ddx"))
362 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
387 fwrite(oss.str().data(), 1, oss.str().length(), out);
407 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
409 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
410 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
413 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
414 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
418 const time_t t = time(0);
421 strm <<
"Last-Modified: " ;
422 if (last_modified > 0)
428 strm <<
"Content-Type: text/xml" <<
CRLF ;
430 strm <<
"Content-Type: text/plain" <<
CRLF ;
434 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
436 strm <<
"Cache-Control: no-cache" <<
CRLF ;
440 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
460 const string &protocol)
462 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
464 strm <<
"XDODS-Server: " <<
DVR<<
CRLF;
465 strm <<
"XOPeNDAP-Server: " <<
DVR<<
CRLF;
470 strm <<
"XDAP: " << protocol <<
CRLF;
472 const time_t t = time(0);
475 strm <<
"Last-Modified: ";
476 if (last_modified > 0)
482 strm <<
"Content-Type: text/xml" <<
CRLF;
484 strm <<
"Content-Type: text/plain" <<
CRLF;
488 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
490 strm <<
"Cache-Control: no-cache" <<
CRLF;
494 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
515 fwrite(oss.str().data(), 1, oss.str().length(), out);
533 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
535 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
536 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
539 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
540 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
544 const time_t t = time(0);
547 strm <<
"Last-Modified: " ;
548 if (last_modified > 0)
553 strm <<
"Content-type: text/html" <<
CRLF ;
555 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
557 strm <<
"Cache-Control: no-cache" <<
CRLF ;
561 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
576 const string &protocol)
578 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
580 strm <<
"XDODS-Server: " <<
DVR<<
CRLF;
581 strm <<
"XOPeNDAP-Server: " <<
DVR<<
CRLF;
586 strm <<
"XDAP: " << protocol <<
CRLF;
588 const time_t t = time(0);
591 strm <<
"Last-Modified: ";
592 if (last_modified > 0)
597 strm <<
"Content-type: text/html" <<
CRLF;
599 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
601 strm <<
"Cache-Control: no-cache" <<
CRLF;
605 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
629 fwrite(oss.str().data(), 1, oss.str().length(), out);
650 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
652 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
653 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
656 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
657 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
661 const time_t t = time(0);
664 strm <<
"Last-Modified: " ;
665 if (last_modified > 0)
670 strm <<
"Content-Type: application/octet-stream" <<
CRLF ;
671 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
673 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
692 const string &protocol)
694 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
696 strm <<
"XDODS-Server: " <<
DVR <<
CRLF;
697 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF;
702 strm <<
"XDAP: " << protocol <<
CRLF;
704 const time_t t = time(0);
707 strm <<
"Last-Modified: ";
708 if (last_modified > 0)
713 strm <<
"Content-Type: application/octet-stream" <<
CRLF;
714 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
716 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
724 const time_t last_modified)
726 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
728 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
729 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
732 strm <<
"XDODS-Server: " << version.c_str() <<
CRLF ;
733 strm <<
"XOPeNDAP-Server: " << version.c_str() <<
CRLF ;
737 const time_t t = time(0);
740 strm <<
"Last-Modified: " ;
741 if (last_modified > 0)
746 strm <<
"Content-Type: Multipart/Related; boundary=" << boundary
747 <<
"; start=\"<" << start <<
">\"; type=\"Text/xml\"" <<
CRLF ;
748 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
750 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
758 const time_t last_modified,
const string &protocol,
const string &url)
760 strm <<
"HTTP/1.1 200 OK" <<
CRLF;
762 const time_t t = time(0);
765 strm <<
"Last-Modified: ";
766 if (last_modified > 0)
771 strm <<
"Content-Type: multipart/related; boundary=" << boundary <<
"; start=\"<" << start
772 <<
">\"; type=\"text/xml\"" <<
CRLF;
776 strm <<
"Content-Description: " << descrip[type] <<
";";
778 strm <<
" url=\"" << url <<
"\"" << CRLF;
783 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
788 strm <<
"X-DAP: " << protocol <<
CRLF;
790 strm <<
"X-OPeNDAP-Server: " <<
DVR<<
CRLF;
798 strm <<
"--" << boundary <<
CRLF;
799 strm <<
"Content-Type: Text/xml; charset=iso-8859-1" <<
CRLF;
800 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
801 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
803 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
811 strm <<
"--" << boundary <<
CRLF;
812 strm <<
"Content-Type: application/octet-stream" <<
CRLF;
813 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
814 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
816 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
844 && (strncmp(line,
CRLF, 2) == 0 || line[0] ==
'\n'))
848 line[slen - 1] =
'\0';
849 if (line[slen - 2] ==
'\r')
850 line[slen - 2] =
'\0';
855 throw Error(
"I expected to find a MIME header, but got EOF instead.");
866 if (strncmp(line,
CRLF, 2) == 0 || line[0] ==
'\n') {
871 line[slen - 1] =
'\0';
872 if (line[slen - 2] ==
'\r')
873 line[slen - 2] =
'\0';
883 string line = raw_line;
884 if (line.find(
'\r') != string::npos)
885 line = line.substr(0, line.size()-1);
889 throw Error(
"I expected to find a MIME header, but got EOF instead.");
901 istringstream iss(header);
904 iss.getline(s, 1023,
':');
907 iss.ignore(1023,
' ');
908 iss.getline(s, 1023);
928 if (strlen(line) < 2 || !(line[0] ==
'-' && line[1] ==
'-'))
931 return strncmp(line, boundary.c_str(), boundary.length()) == 0;
950 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
951 || boundary_line.find(
"--") != 0)
953 "The DAP4 data response document is broken - missing or malformed boundary.");
955 return boundary_line;
964 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
965 || boundary_line.find(
"--") != 0)
967 "The DAP4 data response document is broken - missing or malformed boundary.");
969 return boundary_line;
994 bool ct =
false, cd =
false, ci =
false;
997 while (!header.empty()) {
1001 if (name ==
"content-type") {
1003 if (value.find(content_type) == string::npos)
1004 throw Error(
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
1006 else if (name ==
"content-description") {
1010 "Content-Description for this part of a DAP4 data response must be dap4-ddx or dap4-data-ddx");
1012 else if (name ==
"content-id") {
1014 if (!cid.empty() && value != cid)
1015 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1021 if (!(ct && cd && ci))
throw Error(
"The DAP4 data response document is broken - missing header.");
1026 bool ct =
false, cd =
false, ci =
false;
1029 while (!header.empty()) {
1033 if (name ==
"content-type") {
1035 if (value.find(content_type) == string::npos)
1036 throw Error(
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
1038 else if (name ==
"content-description") {
1042 "Content-Description for this part of a DAP4 data response must be dap4-ddx or dap4-data-ddx");
1044 else if (name ==
"content-id") {
1046 if (!cid.empty() && value != cid)
1047 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1053 if (!(ct && cd && ci))
throw Error(
"The DAP4 data response document is broken - missing header.");
1066 string::size_type offset = cid.find(
"cid:");
1068 throw Error(
"expected CID to start with 'cid:'");
1071 value.append(cid.substr(offset + 4));
1092 fwrite(oss.str().data(), 1, oss.str().length(), out);
1107 strm <<
"HTTP/1.0 " << code <<
" " << reason.c_str() <<
CRLF ;
1108 if (version ==
"") {
1109 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
1110 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
1113 strm <<
"XDODS-Server: " << version.c_str() <<
CRLF ;
1114 strm <<
"XOPeNDAP-Server: " << version.c_str() <<
CRLF ;
1118 const time_t t = time(0);
1120 strm <<
"Cache-Control: no-cache" <<
CRLF ;
1136 fwrite(oss.str().data(), 1, oss.str().length(), out);
1149 strm <<
"HTTP/1.0 304 NOT MODIFIED" <<
CRLF ;
1150 const time_t t = time(0);
1169 found_override(
string name,
string &doc)
1171 ifstream ifs((name +
".ovr").c_str());
1177 while (!ifs.eof()) {
1178 ifs.getline(tmp, 255);
1180 strncat(tmp,
"\n",
sizeof(tmp) - strlen(tmp) - 1);
1203 char *s = fgets(tmp, 255, in);
1204 if (s && strncmp(s,
CRLF, 2) == 0)