44 #ifndef TM_IN_SYS_TIME 50 #include <sys/types.h> 69 #include "mime_util.h" 70 #include "media_types.h" 72 #include "Ancillary.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) ;
194 fprintf(stdout,
"XDAP: %s%s", DAP_PROTOCOL_VERSION, 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;
273 string::size_type delim = path.find_last_of(FILE_DELIMITER);
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")))
350 return 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 ;
415 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
417 const time_t t = time(0);
418 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
420 strm <<
"Last-Modified: " ;
421 if (last_modified > 0)
422 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
426 if (type == dap4_dmr)
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 ;
434 if (type == dods_error)
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;
467 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
469 strm <<
"XDAP: " << protocol << CRLF;
471 const time_t t = time(0);
472 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
474 strm <<
"Last-Modified: ";
475 if (last_modified > 0)
476 strm <<
rfc822_date(last_modified).c_str() << CRLF;
480 if (type == dap4_dmr)
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;
488 if (type == dods_error)
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 ;
541 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
543 const time_t t = time(0);
544 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
546 strm <<
"Last-Modified: " ;
547 if (last_modified > 0)
548 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
552 strm <<
"Content-type: text/html" << CRLF ;
554 strm <<
"Content-Description: " << descrip[type] << CRLF ;
555 if (type == dods_error)
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;
583 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
585 strm <<
"XDAP: " << protocol << CRLF;
587 const time_t t = time(0);
588 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
590 strm <<
"Last-Modified: ";
591 if (last_modified > 0)
592 strm <<
rfc822_date(last_modified).c_str() << CRLF;
596 strm <<
"Content-type: text/html" << CRLF;
598 strm <<
"Content-Description: " << descrip[type] << CRLF;
599 if (type == dods_error)
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 ;
658 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
660 const time_t t = time(0);
661 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
663 strm <<
"Last-Modified: " ;
664 if (last_modified > 0)
665 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
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())
699 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF;
701 strm <<
"XDAP: " << protocol << CRLF;
703 const time_t t = time(0);
704 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
706 strm <<
"Last-Modified: ";
707 if (last_modified > 0)
708 strm <<
rfc822_date(last_modified).c_str() << CRLF;
712 strm <<
"Content-Type: application/octet-stream" << CRLF;
713 strm <<
"Content-Description: " << descrip[type] << CRLF;
715 strm <<
"Content-Encoding: " << encoding[enc] << CRLF;
720 void set_mime_multipart(ostream &strm,
const string &boundary,
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 ;
734 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
736 const time_t t = time(0);
737 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
739 strm <<
"Last-Modified: " ;
740 if (last_modified > 0)
741 strm <<
rfc822_date(last_modified).c_str() << CRLF ;
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);
762 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF;
764 strm <<
"Last-Modified: ";
765 if (last_modified > 0)
766 strm <<
rfc822_date(last_modified).c_str() << CRLF;
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;
785 strm <<
"X-DAP: " << DAP_PROTOCOL_VERSION << CRLF;
787 strm <<
"X-DAP: " << protocol << CRLF;
789 strm <<
"X-OPeNDAP-Server: " << DVR<< CRLF;
794 void set_mime_ddx_boundary(ostream &strm,
const string &boundary,
797 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 ;
808 void set_mime_data_boundary(ostream &strm,
const string &boundary,
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 ;
821 const size_t line_length = 1024;
842 char line[line_length];
844 if (fgets(line, line_length, in)
845 && (strncmp(line, CRLF, 2) == 0 || line[0] ==
'\n'))
848 size_t slen = min(strlen(line), line_length);
849 line[slen - 1] =
'\0';
850 if (line[slen - 2] ==
'\r')
851 line[slen - 2] =
'\0';
856 throw Error(
"I expected to find a MIME header, but got EOF instead.");
876 char line[line_length];
878 in.getline(line, line_length);
879 if (strncmp(line, CRLF, 2) == 0 || line[0] ==
'\n') {
883 size_t slen = min(strlen(line), line_length);
884 line[slen - 1] =
'\0';
885 if (line[slen - 2] ==
'\r')
886 line[slen - 2] =
'\0';
893 char raw_line[line_length];
895 in.getline(raw_line, line_length);
896 string line = raw_line;
897 if (line.find(
'\r') != string::npos)
898 line = line.substr(0, line.size()-1);
902 throw Error(
"I expected to find a MIME header, but got EOF instead.");
914 istringstream iss(header);
916 size_t length = header.length() + 1;
917 vector<char> s(length);
919 iss.getline(&s[0], length,
':');
922 iss.ignore(length,
' ');
923 iss.getline(&s[0], length);
943 if (strlen(line) < 2 || !(line[0] ==
'-' && line[1] ==
'-'))
946 return strncmp(line, boundary.c_str(), boundary.length()) == 0;
965 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
966 || boundary_line.find(
"--") != 0)
967 throw Error(internal_error,
"The DAP4 data response document is broken - missing or malformed boundary.");
969 return boundary_line;
978 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
979 || boundary_line.find(
"--") != 0)
980 throw Error(internal_error,
"The DAP4 data response document is broken - missing or malformed boundary.");
982 return boundary_line;
1007 bool ct =
false, cd =
false, ci =
false;
1012 while (!header.empty()) {
1016 if (name ==
"content-type") {
1018 if (value.find(content_type) == string::npos)
1019 throw Error(internal_error,
"Content-Type for this part of a DAP2 data ddx response must be " + content_type +
".");
1021 else if (name ==
"content-description") {
1024 throw Error(internal_error,
"Content-Description for this part of a DAP2 data ddx response must be dods-ddx or dods-data-ddx");
1026 else if (name ==
"content-id") {
1028 if (!cid.empty() && value != cid)
1029 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1035 if (!(ct && cd && ci))
throw Error(internal_error,
"The DAP4 data response document is broken - missing header.");
1040 bool ct =
false, cd =
false, ci =
false;
1043 while (!header.empty()) {
1047 if (name ==
"content-type") {
1049 if (value.find(content_type) == string::npos)
1050 throw Error(internal_error,
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
1052 else if (name ==
"content-description") {
1055 throw Error(
"Content-Description '" + value +
"' not the expected value (expected: " + descrip[object_type] +
").");
1057 else if (name ==
"content-id") {
1059 if (!cid.empty() && value != cid)
1060 throw Error(
"Content-Id mismatch. Expected: " + cid +
", but got: " + value);
1066 if (!(ct && cd && ci))
throw Error(internal_error,
"The DAP4 data response document is broken - missing header.");
1079 string::size_type offset = cid.find(
"cid:");
1081 throw Error(internal_error,
"expected CID to start with 'cid:'");
1084 value.append(cid.substr(offset + 4));
1101 const string &version)
1105 fwrite(oss.str().data(), 1, oss.str().length(), out);
1118 const string &version)
1120 strm <<
"HTTP/1.0 " << code <<
" " << reason.c_str() << CRLF ;
1121 if (version ==
"") {
1122 strm <<
"XDODS-Server: " << DVR << CRLF ;
1123 strm <<
"XOPeNDAP-Server: " << DVR << CRLF ;
1126 strm <<
"XDODS-Server: " << version.c_str() << CRLF ;
1127 strm <<
"XOPeNDAP-Server: " << version.c_str() << CRLF ;
1129 strm <<
"XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
1131 const time_t t = time(0);
1132 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
1133 strm <<
"Cache-Control: no-cache" << CRLF ;
1149 fwrite(oss.str().data(), 1, oss.str().length(), out);
1162 strm <<
"HTTP/1.0 304 NOT MODIFIED" << CRLF ;
1163 const time_t t = time(0);
1164 strm <<
"Date: " <<
rfc822_date(t).c_str() << CRLF ;
1182 found_override(
string name,
string &doc)
1184 ifstream ifs((name +
".ovr").c_str());
1190 while (!ifs.eof()) {
1191 ifs.getline(tmp, 255);
1193 strncat(tmp,
"\n",
sizeof(tmp) - strlen(tmp) - 1);
1216 char *s = fgets(tmp, 255, in);
1217 if (s && strncmp(s, CRLF, 2) == 0)
1236 }
while (!header.empty());
string get_next_mime_header(FILE *in)
void ErrMsgT(const string &Msgt)
Logs an error message.
time_t last_modified_time(const string &name)
string rfc822_date(const time_t t)
void read_multipart_headers(FILE *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.
string read_multipart_boundary(FILE *in, 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)
top level DAP object to house generic methods
void parse_mime_header(const string &header, string &name, string &value)
ObjectType get_description_type(const string &value)
bool remove_mime_header(FILE *in)
Read and discard the MIME header of the stream in.
ObjectType get_type(const string &value)
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
void set_mime_error(FILE *out, int code, const string &reason, const string &version)
string cid_to_header_value(const string &cid)
void set_mime_not_modified(FILE *out)
Send a `Not Modified' response.
bool is_boundary(const char *line, const string &boundary)
void set_mime_html(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
EncodingType
The type of encoding used on the current stream.
A class for error processing.
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.