70#include "media_types.h"
77#define FILE_DELIMITER '\\'
79#define FILE_DELIMITER '/'
99 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
136static const char *days[] =
137 {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
139static const char *months[] =
140 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
141 "Aug",
"Sep",
"Oct",
"Nov",
"Dec"
145#define snprintf sprintf_s
159 const struct tm *ret = gmtime_r(&t, &stm);
165 snprintf(d, 255,
"%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm.tm_wday],
166 stm.tm_mday, months[stm.tm_mon],
168 stm.tm_hour, stm.tm_min, stm.tm_sec);
173static const int TimLen = 26;
190do_version(
const string &script_ver,
const string &dataset_ver)
192 fprintf(stdout,
"HTTP/1.0 200 OK%s", CRLF) ;
193 fprintf(stdout,
"XDODS-Server: %s%s", DVR, CRLF) ;
194 fprintf(stdout,
"XOPeNDAP-Server: %s%s", DVR, CRLF) ;
195 fprintf(stdout,
"XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
196 fprintf(stdout,
"Content-Type: text/plain%s", CRLF) ;
197 fprintf(stdout, CRLF) ;
199 fprintf(stdout,
"Core software version: %s%s", DVR, CRLF) ;
201 if (script_ver !=
"")
202 fprintf(stdout,
"Server Script Revision: %s%s", script_ver.c_str(), CRLF) ;
204 if (dataset_ver !=
"")
205 fprintf(stdout,
"Dataset version: %s%s", dataset_ver.c_str(), CRLF) ;
228 if (time(&TimBin) == (time_t) - 1)
229 strncpy(TimStr,
"time() error ", TimLen-1);
231 char ctime_value[TimLen];
232 const char *ret = ctime_r(&TimBin, ctime_value);
234 strncpy(TimStr,
"Unknown", TimLen-1);
236 strncpy(TimStr, ctime_value, TimLen-1);
237 TimStr[TimLen - 2] =
'\0';
241 cerr <<
"[" << TimStr <<
"] DAP server error: " << Msgt << endl;
271 string::size_type delim = path.find_last_of(FILE_DELIMITER);
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);
293static const char *descrip[] =
294 {
"unknown",
"dods_das",
"dods_dds",
"dods_data",
"dods_ddx",
295 "dods_error",
"web_error",
"dap4-dmr",
"dap4-data",
"dap4-error"
299static const char *descrip[] = {
314static const char *encoding[] =
315 {
"unknown",
"deflate",
"x-plain",
"gzip",
"binary"
339 if ((value == DAS1) || (value ==
"dods-das"))
341 else if ((value ==
"dods_dds") || (value ==
"dods-dds"))
343 else if ((value ==
"dods_data") || (value ==
"dods-data"))
345 else if ((value ==
"dods_ddx") || (value ==
"dods-ddx"))
347 else if ((value ==
"dods_data_ddx" || (value ==
"dods-data-ddx")))
348 return dods_data_ddx;
349 else if ((value ==
"dods_error") || (value ==
"dods-error"))
351 else if ((value ==
"web_error") || (value ==
"web-error"))
354 else if ((value ==
"dap4_dmr") || (value ==
"dap4-dmr") || (value == DMR_Content_Type))
356 else if ((value ==
"dap4_data") || (value ==
"dap4-data") || (value == DAP4_DATA_Content_Type))
358 else if ((value ==
"dap4_error") || (value ==
"dap4-error"))
384 fwrite(oss.str().data(), 1, oss.str().length(), out);
404 strm <<
"HTTP/1.0 200 OK" << CRLF ;
406 strm <<
"XDODS-Server: " << DVR << CRLF ;
407 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
410 strm <<
"XDODS-Server: " << ver.c_str() << CRLF ;
411 strm <<
"XOPeNDAP-Server: " << ver.c_str() << CRLF ;
413 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
415 const time_t t = time(0);
416 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
418 strm <<
"Last-Modified: " ;
419 if (last_modified > 0)
420 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
424 if (type == dap4_dmr)
425 strm <<
"Content-Type: application/vnd.org.opendap.dap4.dataset-metadata+xml" << CRLF ;
427 strm <<
"Content-Type: text/plain" << CRLF ;
431 strm <<
"Content-Description: " << descrip[type] << CRLF ;
432 if (type == dods_error)
433 strm <<
"Cache-Control: no-cache" << CRLF ;
437 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
457 const string &protocol)
459 strm <<
"HTTP/1.0 200 OK" << CRLF;
461 strm <<
"XDODS-Server: " << DVR << CRLF;
462 strm <<
"XOPeNDAP-Server: " << DVR << CRLF;
465 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
467 strm <<
"XDAP: " << protocol << CRLF;
469 const time_t t = time(0);
470 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
472 strm <<
"Last-Modified: ";
473 if (last_modified > 0)
474 strm <<
rfc822_date(last_modified).c_str() << CRLF;
478 if (type == dap4_dmr)
479 strm <<
"Content-Type: application/vnd.org.opendap.dap4.dataset-metadata+xml" << CRLF;
481 strm <<
"Content-Type: text/plain" << CRLF;
485 strm <<
"Content-Description: " << descrip[type] << CRLF;
486 if (type == dods_error)
487 strm <<
"Cache-Control: no-cache" << CRLF;
491 strm <<
"Content-Encoding: " << encoding[enc] << CRLF;
512 fwrite(oss.str().data(), 1, oss.str().length(), out);
530 strm <<
"HTTP/1.0 200 OK" << CRLF ;
532 strm <<
"XDODS-Server: " << DVR << CRLF ;
533 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
536 strm <<
"XDODS-Server: " << ver.c_str() << CRLF ;
537 strm <<
"XOPeNDAP-Server: " << ver.c_str() << CRLF ;
539 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
541 const time_t t = time(0);
542 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
544 strm <<
"Last-Modified: " ;
545 if (last_modified > 0)
546 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
550 strm <<
"Content-type: text/html" << CRLF ;
552 strm <<
"Content-Description: " << descrip[type] << CRLF ;
553 if (type == dods_error)
554 strm <<
"Cache-Control: no-cache" << CRLF ;
558 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
573 const string &protocol)
575 strm <<
"HTTP/1.0 200 OK" << CRLF;
577 strm <<
"XDODS-Server: " << DVR<< CRLF;
578 strm <<
"XOPeNDAP-Server: " << DVR<< CRLF;
581 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
583 strm <<
"XDAP: " << protocol << CRLF;
585 const time_t t = time(0);
586 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
588 strm <<
"Last-Modified: ";
589 if (last_modified > 0)
590 strm <<
rfc822_date(last_modified).c_str() << CRLF;
594 strm <<
"Content-type: text/html" << CRLF;
596 strm <<
"Content-Description: " << descrip[type] << CRLF;
597 if (type == dods_error)
598 strm <<
"Cache-Control: no-cache" << CRLF;
602 strm <<
"Content-Encoding: " << encoding[enc] << CRLF;
626 fwrite(oss.str().data(), 1, oss.str().length(), out);
647 strm <<
"HTTP/1.0 200 OK" << CRLF ;
649 strm <<
"XDODS-Server: " << DVR << CRLF ;
650 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
653 strm <<
"XDODS-Server: " << ver.c_str() << CRLF ;
654 strm <<
"XOPeNDAP-Server: " << ver.c_str() << CRLF ;
656 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
658 const time_t t = time(0);
659 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
661 strm <<
"Last-Modified: " ;
662 if (last_modified > 0)
663 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
667 strm <<
"Content-Type: application/octet-stream" << CRLF ;
668 strm <<
"Content-Description: " << descrip[type] << CRLF ;
670 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
689 const string &protocol)
691 strm <<
"HTTP/1.0 200 OK" << CRLF;
693 strm <<
"XDODS-Server: " << DVR << CRLF;
694 strm <<
"XOPeNDAP-Server: " << DVR << CRLF;
696 if (protocol.empty())
697 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
699 strm <<
"XDAP: " << protocol << CRLF;
701 const time_t t = time(0);
702 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
704 strm <<
"Last-Modified: ";
705 if (last_modified > 0)
706 strm <<
rfc822_date(last_modified).c_str() << CRLF;
710 strm <<
"Content-Type: application/octet-stream" << CRLF;
711 strm <<
"Content-Description: " << descrip[type] << CRLF;
713 strm <<
"Content-Encoding: " << encoding[enc] << CRLF;
718void set_mime_multipart(ostream &strm,
const string &boundary,
719 const string &start, ObjectType type,
721 const time_t last_modified)
723 strm <<
"HTTP/1.0 200 OK" << CRLF ;
725 strm <<
"XDODS-Server: " << DVR << CRLF ;
726 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
729 strm <<
"XDODS-Server: " << version.c_str() << CRLF ;
730 strm <<
"XOPeNDAP-Server: " << version.c_str() << CRLF ;
732 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
734 const time_t t = time(0);
735 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
737 strm <<
"Last-Modified: " ;
738 if (last_modified > 0)
739 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
743 strm <<
"Content-Type: Multipart/Related; boundary=" << boundary
744 <<
"; start=\"<" << start <<
">\"; type=\"Text/xml\"" << CRLF ;
745 strm <<
"Content-Description: " << descrip[type] << CRLF ;
747 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
755 const time_t last_modified,
const string &protocol,
const string &url)
757 strm <<
"HTTP/1.1 200 OK" << CRLF;
759 const time_t t = time(0);
760 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
762 strm <<
"Last-Modified: ";
763 if (last_modified > 0)
764 strm <<
rfc822_date(last_modified).c_str() << CRLF;
768 strm <<
"Content-Type: multipart/related; boundary=" << boundary <<
"; start=\"<" << start
769 <<
">\"; type=\"text/xml\"" << CRLF;
773 strm <<
"Content-Description: " << descrip[type] <<
";";
775 strm <<
" url=\"" << url <<
"\"" << CRLF;
780 strm <<
"Content-Encoding: " << encoding[enc] << CRLF;
783 strm <<
"X-DAP: " << DAP_PROTOCOL_VERSION << CRLF;
785 strm <<
"X-DAP: " << protocol << CRLF;
787 strm <<
"X-OPeNDAP-Server: " << DVR<< CRLF;
792void set_mime_ddx_boundary(ostream &strm,
const string &boundary,
795 strm <<
"--" << boundary << CRLF;
797 strm <<
"Content-Type: Text/xml; charset=iso-8859-1" << CRLF;
798 strm <<
"Content-Id: <" << cid <<
">" << CRLF;
799 strm <<
"Content-Description: " << descrip[type] << CRLF ;
801 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
806void set_mime_data_boundary(ostream &strm,
const string &boundary,
809 strm <<
"--" << boundary << CRLF;
810 strm <<
"Content-Type: application/octet-stream" << CRLF;
811 strm <<
"Content-Id: <" << cid <<
">" << CRLF;
812 strm <<
"Content-Description: " << descrip[type] << CRLF ;
814 strm <<
"Content-Encoding: " << encoding[enc] << CRLF ;
819const size_t line_length = 1024;
840 char line[line_length];
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.");
874 char line[line_length];
876 in.getline(line, line_length);
877 if (strncmp(line, CRLF, 2) == 0 || line[0] ==
'\n') {
881 size_t slen = min(strlen(line), line_length);
882 line[slen - 1] =
'\0';
883 if (line[slen - 2] ==
'\r')
884 line[slen - 2] =
'\0';
891 char raw_line[line_length];
893 in.getline(raw_line, line_length);
894 string line = raw_line;
895 if (line.find(
'\r') != string::npos)
896 line = line.substr(0, line.size()-1);
900 throw Error(
"I expected to find a MIME header, but got EOF instead.");
912 istringstream iss(header);
914 size_t length = header.length() + 1;
915 vector<char> s(length);
917 iss.getline(s.data(), length,
':');
920 iss.ignore(length,
' ');
921 iss.getline(s.data(), length);
941 if (strlen(line) < 2 || !(line[0] ==
'-' && line[1] ==
'-'))
944 return strncmp(line, boundary.c_str(), boundary.length()) == 0;
963 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
964 || boundary_line.find(
"--") != 0)
965 throw Error(internal_error,
"The DAP4 data response document is broken - missing or malformed boundary.");
967 return boundary_line;
976 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
977 || boundary_line.find(
"--") != 0)
978 throw Error(internal_error,
"The DAP4 data response document is broken - missing or malformed boundary.");
980 return boundary_line;
1005 bool ct =
false, cd =
false, ci =
false;
1010 while (!header.empty()) {
1014 if (name ==
"content-type") {
1016 if (value.find(content_type) == string::npos)
1017 throw Error(internal_error,
"Content-Type for this part of a DAP2 data ddx response must be " + content_type +
".");
1019 else if (name ==
"content-description") {
1022 throw Error(internal_error,
"Content-Description for this part of a DAP2 data ddx response must be dods-ddx or dods-data-ddx");
1024 else if (name ==
"content-id") {
1026 if (!cid.empty() && value != cid)
1027 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1033 if (!(ct && cd && ci))
throw Error(internal_error,
"The DAP4 data response document is broken - missing header.");
1036void read_multipart_headers(istream &in,
const string &content_type,
const ObjectType object_type,
const string &cid)
1038 bool ct =
false, cd =
false, ci =
false;
1041 while (!header.empty()) {
1045 if (name ==
"content-type") {
1047 if (value.find(content_type) == string::npos)
1048 throw Error(internal_error,
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
1050 else if (name ==
"content-description") {
1053 throw Error(
"Content-Description '" + value +
"' not the expected value (expected: " + descrip[object_type] +
").");
1055 else if (name ==
"content-id") {
1057 if (!cid.empty() && value != cid)
1058 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1064 if (!(ct && cd && ci))
throw Error(internal_error,
"The DAP4 data response document is broken - missing header.");
1077 string::size_type offset = cid.find(
"cid:");
1079 throw Error(internal_error,
"expected CID to start with 'cid:'");
1082 value.append(cid.substr(offset + 4));
1099 const string &version)
1103 fwrite(oss.str().data(), 1, oss.str().length(), out);
1116 const string &version)
1118 strm <<
"HTTP/1.0 " << code <<
" " << reason.c_str() << CRLF ;
1119 if (version ==
"") {
1120 strm <<
"XDODS-Server: " << DVR << CRLF ;
1121 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
1124 strm <<
"XDODS-Server: " << version.c_str() << CRLF ;
1125 strm <<
"XOPeNDAP-Server: " << version.c_str() << CRLF ;
1127 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
1129 const time_t t = time(0);
1130 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
1131 strm <<
"Cache-Control: no-cache" << CRLF ;
1147 fwrite(oss.str().data(), 1, oss.str().length(), out);
1160 strm <<
"HTTP/1.0 304 NOT MODIFIED" << CRLF ;
1161 const time_t t = time(0);
1162 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
1180found_override(
string name,
string &doc)
1182 ifstream ifs((name +
".ovr").c_str());
1188 while (!ifs.eof()) {
1189 ifs.getline(tmp, 255);
1191 strncat(tmp,
"\n",
sizeof(tmp) - strlen(tmp) - 1);
1214 char *s = fgets(tmp, 255, in);
1215 if (s && strncmp(s, CRLF, 2) == 0)
1234 }
while (!header.empty());
A class for error processing.
top level DAP object to house generic methods
string read_multipart_boundary(FILE *in, const string &boundary)
void set_mime_error(FILE *out, int code, const string &reason, const string &version)
void set_mime_html(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
ObjectType get_description_type(const string &value)
string cid_to_header_value(const string &cid)
void parse_mime_header(const string &header, string &name, string &value)
time_t last_modified_time(const string &name)
string name_path(const string &path)
Returns the filename portion of a pathname.
void set_mime_not_modified(FILE *out)
Send a ‘Not Modified’ response.
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.
bool remove_mime_header(FILE *in)
Read and discard the MIME header of the stream in.
void read_multipart_headers(FILE *in, const string &content_type, const ObjectType object_type, const string &cid)
EncodingType
The type of encoding used on the current stream.
void ErrMsgT(const string &Msgt)
Logs an error message.
ObjectType get_type(const string &value)
string rfc822_date(const time_t t)
bool is_boundary(const char *line, const string &boundary)
ObjectType
The type of object in the stream coming from the data server.
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
string get_next_mime_header(FILE *in)