44 #ifndef TM_IN_SYS_TIME
50 #include <sys/types.h>
77 #define FILE_DELIMITER '\\'
78 #else // default to unix
79 #define FILE_DELIMITER '/'
83 #define CRLF "\r\n" // Change here, expr-test.cc, in DODSFilter and ResponseBuilder
99 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
136 static const char *days[] =
137 {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
139 static const char *months[] =
140 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
141 "Aug",
"Sep",
"Oct",
"Nov",
"Dec"
145 #define snprintf sprintf_s
158 struct tm *stm = gmtime(&t);
164 snprintf(d, 255,
"%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday],
165 stm->tm_mday, months[stm->tm_mon],
167 stm->tm_hour, stm->tm_min, stm->tm_sec);
172 static const int TimLen = 26;
189 do_version(
const string &script_ver,
const string &dataset_ver)
191 fprintf(stdout,
"HTTP/1.0 200 OK%s",
CRLF) ;
192 fprintf(stdout,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
193 fprintf(stdout,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
195 fprintf(stdout,
"Content-Type: text/plain%s",
CRLF) ;
196 fprintf(stdout,
CRLF) ;
198 fprintf(stdout,
"Core software version: %s%s",
DVR,
CRLF) ;
200 if (script_ver !=
"")
201 fprintf(stdout,
"Server Script Revision: %s%s", script_ver.c_str(),
CRLF) ;
203 if (dataset_ver !=
"")
204 fprintf(stdout,
"Dataset version: %s%s", dataset_ver.c_str(),
CRLF) ;
227 if (time(&TimBin) == (time_t) - 1)
228 strncpy(TimStr,
"time() error ", TimLen-1);
230 char *ctime_value = ctime(&TimBin);
232 strncpy(TimStr,
"Unknown", TimLen-1);
234 strncpy(TimStr, ctime_value, TimLen-1);
235 TimStr[TimLen - 2] =
'\0';
238 strncpy(TimStr, ctime(&TimBin), TimLen-1);
239 TimStr[TimLen - 2] =
'\0';
243 cerr <<
"[" << TimStr <<
"] DAP server error: " << Msgt << endl;
274 string::size_type pound = path.find_last_of(
"#");
277 if (pound != string::npos)
278 new_path = path.substr(pound + 1);
280 new_path = path.substr(delim + 1);
295 static const char *descrip[] =
296 {
"unknown",
"dods_das",
"dods_dds",
"dods_data",
"dods_ddx",
297 "dods_error",
"web_error",
"dap4-dmr",
"dap4-data",
"dap4-error"
301 static const char *descrip[] = {
316 static const char *encoding[] =
317 {
"unknown",
"deflate",
"x-plain",
"gzip",
"binary"
341 if ((value == DAS1) || (value ==
"dods-das"))
343 else if ((value ==
"dods_dds") || (value ==
"dods-dds"))
345 else if ((value ==
"dods_data") || (value ==
"dods-data"))
347 else if ((value ==
"dods_ddx") || (value ==
"dods-ddx"))
349 else if ((value ==
"dods_data_ddx" || (value ==
"dods-data-ddx")))
351 else if ((value ==
"dods_error") || (value ==
"dods-error"))
353 else if ((value ==
"web_error") || (value ==
"web-error"))
356 else if ((value ==
"dap4_dmr") || (value ==
"dap4-dmr") || (value == DMR_Content_Type))
358 else if ((value ==
"dap4_data") || (value ==
"dap4-data") || (value == DAP4_DATA_Content_Type))
360 else if ((value ==
"dap4_error") || (value ==
"dap4-error"))
386 fwrite(oss.str().data(), 1, oss.str().length(), out);
406 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
408 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
409 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
412 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
413 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
417 const time_t t = time(0);
420 strm <<
"Last-Modified: " ;
421 if (last_modified > 0)
427 strm <<
"Content-Type: application/vnd.org.opendap.dap4.dataset-metadata+xml" <<
CRLF ;
429 strm <<
"Content-Type: text/plain" <<
CRLF ;
433 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
435 strm <<
"Cache-Control: no-cache" <<
CRLF ;
439 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
459 const string &protocol)
461 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
463 strm <<
"XDODS-Server: " <<
DVR <<
CRLF;
464 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF;
469 strm <<
"XDAP: " << protocol <<
CRLF;
471 const time_t t = time(0);
474 strm <<
"Last-Modified: ";
475 if (last_modified > 0)
481 strm <<
"Content-Type: application/vnd.org.opendap.dap4.dataset-metadata+xml" <<
CRLF;
483 strm <<
"Content-Type: text/plain" <<
CRLF;
487 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
489 strm <<
"Cache-Control: no-cache" <<
CRLF;
493 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
514 fwrite(oss.str().data(), 1, oss.str().length(), out);
532 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
534 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
535 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
538 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
539 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
543 const time_t t = time(0);
546 strm <<
"Last-Modified: " ;
547 if (last_modified > 0)
552 strm <<
"Content-type: text/html" <<
CRLF ;
554 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
556 strm <<
"Cache-Control: no-cache" <<
CRLF ;
560 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
575 const string &protocol)
577 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
579 strm <<
"XDODS-Server: " <<
DVR<<
CRLF;
580 strm <<
"XOPeNDAP-Server: " <<
DVR<<
CRLF;
585 strm <<
"XDAP: " << protocol <<
CRLF;
587 const time_t t = time(0);
590 strm <<
"Last-Modified: ";
591 if (last_modified > 0)
596 strm <<
"Content-type: text/html" <<
CRLF;
598 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
600 strm <<
"Cache-Control: no-cache" <<
CRLF;
604 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
628 fwrite(oss.str().data(), 1, oss.str().length(), out);
649 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
651 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
652 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
655 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
656 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
660 const time_t t = time(0);
663 strm <<
"Last-Modified: " ;
664 if (last_modified > 0)
669 strm <<
"Content-Type: application/octet-stream" <<
CRLF ;
670 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
672 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
691 const string &protocol)
693 strm <<
"HTTP/1.0 200 OK" <<
CRLF;
695 strm <<
"XDODS-Server: " <<
DVR <<
CRLF;
696 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF;
698 if (protocol.empty())
701 strm <<
"XDAP: " << protocol <<
CRLF;
703 const time_t t = time(0);
706 strm <<
"Last-Modified: ";
707 if (last_modified > 0)
712 strm <<
"Content-Type: application/octet-stream" <<
CRLF;
713 strm <<
"Content-Description: " << descrip[type] <<
CRLF;
715 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
723 const time_t last_modified)
725 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
727 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
728 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
731 strm <<
"XDODS-Server: " << version.c_str() <<
CRLF ;
732 strm <<
"XOPeNDAP-Server: " << version.c_str() <<
CRLF ;
736 const time_t t = time(0);
739 strm <<
"Last-Modified: " ;
740 if (last_modified > 0)
745 strm <<
"Content-Type: Multipart/Related; boundary=" << boundary
746 <<
"; start=\"<" << start <<
">\"; type=\"Text/xml\"" <<
CRLF ;
747 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
749 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
757 const time_t last_modified,
const string &protocol,
const string &url)
759 strm <<
"HTTP/1.1 200 OK" <<
CRLF;
761 const time_t t = time(0);
764 strm <<
"Last-Modified: ";
765 if (last_modified > 0)
770 strm <<
"Content-Type: multipart/related; boundary=" << boundary <<
"; start=\"<" << start
771 <<
">\"; type=\"text/xml\"" <<
CRLF;
775 strm <<
"Content-Description: " << descrip[type] <<
";";
777 strm <<
" url=\"" << url <<
"\"" << CRLF;
782 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF;
787 strm <<
"X-DAP: " << protocol <<
CRLF;
789 strm <<
"X-OPeNDAP-Server: " <<
DVR<<
CRLF;
797 strm <<
"--" << boundary <<
CRLF;
798 strm <<
"Content-Type: Text/xml; charset=iso-8859-1" <<
CRLF;
799 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
800 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
802 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
810 strm <<
"--" << boundary <<
CRLF;
811 strm <<
"Content-Type: application/octet-stream" <<
CRLF;
812 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
813 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
815 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
842 if (fgets(line, line_length, in)
843 && (strncmp(line,
CRLF, 2) == 0 || line[0] ==
'\n'))
846 size_t slen = min(strlen(line), line_length);
847 line[slen - 1] =
'\0';
848 if (line[slen - 2] ==
'\r')
849 line[slen - 2] =
'\0';
854 throw Error(
"I expected to find a MIME header, but got EOF instead.");
864 in.getline(line, line_length);
865 if (strncmp(line,
CRLF, 2) == 0 || line[0] ==
'\n') {
869 size_t slen = min(strlen(line), line_length);
870 line[slen - 1] =
'\0';
871 if (line[slen - 2] ==
'\r')
872 line[slen - 2] =
'\0';
881 in.getline(raw_line, line_length);
882 string line = raw_line;
883 if (line.find(
'\r') != string::npos)
884 line = line.substr(0, line.size()-1);
888 throw Error(
"I expected to find a MIME header, but got EOF instead.");
900 istringstream iss(header);
902 size_t length = header.length() + 1;
903 vector<char> s(length);
905 iss.getline(&s[0], length,
':');
908 iss.ignore(length,
' ');
909 iss.getline(&s[0], length);
929 if (strlen(line) < 2 || !(line[0] ==
'-' && line[1] ==
'-'))
932 return strncmp(line, boundary.c_str(), boundary.length()) == 0;
951 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
952 || boundary_line.find(
"--") != 0)
954 "The DAP4 data response document is broken - missing or malformed boundary.");
956 return boundary_line;
965 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
966 || boundary_line.find(
"--") != 0)
968 "The DAP4 data response document is broken - missing or malformed boundary.");
970 return boundary_line;
995 bool ct =
false, cd =
false, ci =
false;
998 while (!header.empty()) {
1002 if (name ==
"content-type") {
1004 if (value.find(content_type) == string::npos)
1005 throw Error(
"Content-Type for this part of a DAP2 data ddx response must be " + content_type +
".");
1007 else if (name ==
"content-description") {
1011 "Content-Description for this part of a DAP2 data ddx response must be dods-ddx or dods-data-ddx");
1013 else if (name ==
"content-id") {
1015 if (!cid.empty() && value != cid)
1016 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1022 if (!(ct && cd && ci))
throw Error(
"The DAP4 data response document is broken - missing header.");
1027 bool ct =
false, cd =
false, ci =
false;
1030 while (!header.empty()) {
1034 if (name ==
"content-type") {
1036 if (value.find(content_type) == string::npos)
1037 throw Error(
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
1039 else if (name ==
"content-description") {
1042 throw Error(
"Content-Description '" + value +
"' not the expected value (expected: " + descrip[object_type] +
").");
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)
1223 }
while (!header.empty());
void set_mime_not_modified(ostream &strm)
Send a `Not Modified' response.
void ErrMsgT(const string &Msgt)
Logs an error message.
void set_mime_data_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
time_t last_modified_time(const string &name)
string rfc822_date(const time_t t)
void set_mime_multipart(ostream &strm, const string &boundary, const string &start, ObjectType type, EncodingType enc, const time_t last_modified, const string &protocol, const string &url)
string read_multipart_boundary(istream &in, const string &boundary)
ObjectType
The type of object in the stream coming from the data server.
string cid_to_header_value(const string &cid)
void set_mime_text(ostream &strm, ObjectType type, EncodingType enc, const time_t last_modified, const string &protocol)
string get_next_mime_header(istream &in)
void parse_mime_header(const string &header, string &name, string &value)
ObjectType get_description_type(const string &value)
void set_mime_ddx_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
ObjectType get_type(const string &value)
void set_mime_error(ostream &strm, int code, const string &reason, const string &version)
void read_multipart_headers(istream &in, const string &content_type, const ObjectType object_type, const string &cid)
string name_path(const string &path)
Returns the filename portion of a pathname.
bool is_boundary(const char *line, const string &boundary)
void set_mime_html(ostream &strm, ObjectType type, EncodingType enc, const time_t last_modified, const string &protocol)
void set_mime_binary(ostream &strm, ObjectType type, EncodingType enc, const time_t last_modified, const string &protocol)
EncodingType
The type of encoding used on the current stream.
A class for error processing.
#define DAP_PROTOCOL_VERSION
void remove_mime_header(istream &in)
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.