42 {
"$Id: mime_util.cc 22703 2010-05-11 18:10:01Z jimg $" 49 #ifndef TM_IN_SYS_TIME 55 #include <sys/types.h> 80 #define FILE_DELIMITER '\\' 81 #else // default to unix 82 #define FILE_DELIMITER '/' 86 #define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc 92 static const int TimLen = 26;
93 static const int CLUMP_SIZE = 1024;
109 do_version(
const string &script_ver,
const string &dataset_ver)
111 fprintf(stdout,
"HTTP/1.0 200 OK%s",
CRLF) ;
112 fprintf(stdout,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
113 fprintf(stdout,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
115 fprintf(stdout,
"Content-Type: text/plain%s",
CRLF) ;
116 fprintf(stdout,
CRLF) ;
118 fprintf(stdout,
"Core software version: %s%s",
DVR,
CRLF) ;
120 if (script_ver !=
"")
121 fprintf(stdout,
"Server Script Revision: %s%s", script_ver.c_str(),
CRLF) ;
123 if (dataset_ver !=
"")
124 fprintf(stdout,
"Dataset version: %s%s", dataset_ver.c_str(),
CRLF) ;
146 if (time(&TimBin) == (time_t) - 1)
147 strncpy(TimStr,
"time() error ", TimLen-1);
149 strncpy(TimStr, ctime(&TimBin), TimLen-1);
150 TimStr[TimLen - 2] =
'\0';
153 cerr <<
"[" << TimStr <<
"] DAP server error: " << Msgt << endl;
184 string::size_type pound = path.find_last_of(
"#");
187 if (pound != string::npos)
188 new_path = path.substr(pound + 1);
190 new_path = path.substr(delim + 1);
227 static const char *days[] =
228 {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat" 230 static const char *months[] =
231 {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
232 "Aug",
"Sep",
"Oct",
"Nov",
"Dec" 236 #define snprintf sprintf_s 249 struct tm *stm = gmtime(&t);
252 snprintf(d, 255,
"%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday],
253 stm->tm_mday, months[stm->tm_mon],
255 stm->tm_hour, stm->tm_min, stm->tm_sec);
270 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
286 static const char *descrip[] =
287 {
"unknown",
"dods_das",
"dods_dds",
"dods_data",
288 "dods_error",
"web_error",
"dap4-ddx",
"dap4-data",
"dap4-error",
289 "dap4-data-ddx",
"dods_ddx" 291 static const char *encoding[] =
292 {
"unknown",
"deflate",
"x-plain",
"gzip",
"binary" 303 if ((value ==
"dods_das") | (value ==
"dods-das"))
305 else if ((value ==
"dods_dds") | (value ==
"dods-dds"))
307 else if ((value ==
"dods_data") | (value ==
"dods-data"))
309 else if ((value ==
"dods_error") | (value ==
"dods-error"))
311 else if ((value ==
"web_error") | (value ==
"web-error"))
313 else if ((value ==
"dap4_ddx") | (value ==
"dap4-ddx"))
315 else if ((value ==
"dap4_data") | (value ==
"dap4-data"))
317 else if ((value ==
"dap4_error") | (value ==
"dap4-error"))
319 else if ((value ==
"dap4_data_ddx") | (value ==
"dap4-data-ddx"))
321 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
335 if ((value ==
"dods_das") | (value ==
"dods-das"))
337 else if ((value ==
"dods_dds") | (value ==
"dods-dds"))
339 else if ((value ==
"dods_data") | (value ==
"dods-data"))
341 else if ((value ==
"dods_error") | (value ==
"dods-error"))
343 else if ((value ==
"web_error") | (value ==
"web-error"))
345 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
347 else if ((value ==
"dap4_ddx") | (value ==
"dap4-ddx"))
349 else if ((value ==
"dap4_data") | (value ==
"dap4-data"))
351 else if ((value ==
"dap4_error") | (value ==
"dap4-error"))
353 else if ((value ==
"dap4_data_ddx") | (value ==
"dap4-data-ddx"))
355 else if ((value ==
"dods_ddx") | (value ==
"dods-ddx"))
378 fprintf(out,
"HTTP/1.0 200 OK%s",
CRLF) ;
380 fprintf(out,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
381 fprintf(out,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
384 fprintf(out,
"XDODS-Server: %s%s", ver.c_str(),
CRLF) ;
385 fprintf(out,
"XOPeNDAP-Server: %s%s", ver.c_str(),
CRLF) ;
389 const time_t t = time(0);
392 fprintf(out,
"Last-Modified: ") ;
393 if (last_modified > 0)
399 fprintf(out,
"Content-Type: text/xml%s",
CRLF) ;
401 fprintf(out,
"Content-Type: text/plain%s",
CRLF) ;
405 fprintf(out,
"Content-Description: %s%s", descrip[type],
CRLF) ;
407 fprintf(out,
"Cache-Control: no-cache%s",
CRLF) ;
411 fprintf(out,
"Content-Encoding: %s%s", encoding[enc],
CRLF) ;
432 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
434 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
435 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
438 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
439 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
443 const time_t t = time(0);
446 strm <<
"Last-Modified: " ;
447 if (last_modified > 0)
453 strm <<
"Content-Type: text/xml" <<
CRLF ;
455 strm <<
"Content-Type: text/plain" <<
CRLF ;
459 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
461 strm <<
"Cache-Control: no-cache" <<
CRLF ;
465 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
484 fprintf(out,
"HTTP/1.0 200 OK%s",
CRLF) ;
486 fprintf(out,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
487 fprintf(out,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
490 fprintf(out,
"XDODS-Server: %s%s", ver.c_str(),
CRLF) ;
491 fprintf(out,
"XOPeNDAP-Server: %s%s", ver.c_str(),
CRLF) ;
495 const time_t t = time(0);
498 fprintf(out,
"Last-Modified: ") ;
499 if (last_modified > 0)
504 fprintf(out,
"Content-type: text/html%s",
CRLF) ;
506 fprintf(out,
"Content-Description: %s%s", descrip[type],
CRLF) ;
508 fprintf(out,
"Cache-Control: no-cache%s",
CRLF) ;
512 fprintf(out,
"Content-Encoding: %s%s", encoding[enc],
CRLF) ;
531 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
533 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
534 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
537 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
538 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
542 const time_t t = time(0);
545 strm <<
"Last-Modified: " ;
546 if (last_modified > 0)
551 strm <<
"Content-type: text/html" <<
CRLF ;
553 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
555 strm <<
"Cache-Control: no-cache" <<
CRLF ;
559 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
581 fprintf(out,
"HTTP/1.0 200 OK%s",
CRLF) ;
583 fprintf(out,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
584 fprintf(out,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
587 fprintf(out,
"XDODS-Server: %s%s", ver.c_str(),
CRLF) ;
588 fprintf(out,
"XOPeNDAP-Server: %s%s", ver.c_str(),
CRLF) ;
592 const time_t t = time(0);
595 fprintf(out,
"Last-Modified: ") ;
596 if (last_modified > 0)
601 fprintf(out,
"Content-Type: application/octet-stream%s",
CRLF) ;
602 fprintf(out,
"Content-Description: %s%s", descrip[type],
CRLF) ;
604 fprintf(out,
"Content-Encoding: %s%s", encoding[enc],
CRLF) ;
627 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
629 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
630 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
633 strm <<
"XDODS-Server: " << ver.c_str() <<
CRLF ;
634 strm <<
"XOPeNDAP-Server: " << ver.c_str() <<
CRLF ;
638 const time_t t = time(0);
641 strm <<
"Last-Modified: " ;
642 if (last_modified > 0)
647 strm <<
"Content-Type: application/octet-stream" <<
CRLF ;
648 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
650 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
658 const time_t last_modified)
660 strm <<
"HTTP/1.0 200 OK" <<
CRLF ;
662 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
663 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
666 strm <<
"XDODS-Server: " << version.c_str() <<
CRLF ;
667 strm <<
"XOPeNDAP-Server: " << version.c_str() <<
CRLF ;
671 const time_t t = time(0);
674 strm <<
"Last-Modified: " ;
675 if (last_modified > 0)
680 strm <<
"Content-Type: Multipart/Related; boundary=" << boundary
681 <<
"; start=\"<" << start <<
">\"; type=\"Text/xml\"" <<
CRLF ;
682 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
684 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
692 strm <<
"--" << boundary <<
CRLF;
693 strm <<
"Content-Type: Text/xml; charset=iso-8859-1" <<
CRLF;
694 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
695 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
697 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
705 strm <<
"--" << boundary <<
CRLF;
706 strm <<
"Content-Type: application/octet-stream" <<
CRLF;
707 strm <<
"Content-Id: <" << cid <<
">" <<
CRLF;
708 strm <<
"Content-Description: " << descrip[type] <<
CRLF ;
710 strm <<
"Content-Encoding: " << encoding[enc] <<
CRLF ;
736 if (fgets(line, line_length, in)
737 && (strncmp(line,
CRLF, 2) == 0 || line[0] ==
'\n'))
740 size_t slen = min(strlen(line), line_length);
741 line[slen - 1] =
'\0';
742 if (line[slen - 2] ==
'\r')
743 line[slen - 2] =
'\0';
748 throw Error(
"I expected to find a MIME header, but got EOF instead.");
760 istringstream iss(header);
763 iss.getline(s, 1023,
':');
766 iss.ignore(1023,
' ');
767 iss.getline(s, 1023);
783 if (!(line[0] ==
'-' && line[1] ==
'-'))
786 return strncmp(line, boundary.c_str(), boundary.length()) == 0;
804 if ((!boundary.empty() &&
is_boundary(boundary_line.c_str(), boundary))
805 || boundary_line.find(
"--") != 0)
807 "The DAP4 data response document is broken - missing or malformed boundary.");
809 return boundary_line;
833 const ObjectType object_type,
const string &cid)
835 bool ct =
false, cd =
false, ci =
false;
838 while (!header.empty()) {
842 if (name ==
"content-type") {
844 if (value.find(content_type) == string::npos)
845 throw Error(
"Content-Type for this part of a DAP4 data response must be " + content_type +
".");
847 else if (name ==
"content-description") {
850 throw Error(
"Content-Description for this part of a DAP4 data response must be dap4-ddx or dap4-data-ddx");
852 else if (name ==
"content-id") {
854 if (!cid.empty() && value != cid)
855 throw Error(
"Content-Id mismatch. Expected: " + cid
856 +
", but got: " + value);
862 if (!(ct && cd && ci))
863 throw Error(
"The DAP4 data response document is broken - missing header.");
874 string::size_type offset = cid.find(
"cid:");
876 throw Error(
"expected CID to start with 'cid:'");
879 value.append(cid.substr(offset + 4));
897 fprintf(out,
"HTTP/1.0 %d %s%s", code, reason.c_str(),
CRLF) ;
899 fprintf(out,
"XDODS-Server: %s%s",
DVR,
CRLF) ;
900 fprintf(out,
"XOPeNDAP-Server: %s%s",
DVR,
CRLF) ;
903 fprintf(out,
"XDODS-Server: %s%s", version.c_str(),
CRLF) ;
904 fprintf(out,
"XOPeNDAP-Server: %s%s", version.c_str(),
CRLF) ;
908 const time_t t = time(0);
910 fprintf(out,
"Cache-Control: no-cache%s",
CRLF) ;
925 strm <<
"HTTP/1.0 " << code <<
" " << reason.c_str() <<
CRLF ;
927 strm <<
"XDODS-Server: " <<
DVR <<
CRLF ;
928 strm <<
"XOPeNDAP-Server: " <<
DVR <<
CRLF ;
931 strm <<
"XDODS-Server: " << version.c_str() <<
CRLF ;
932 strm <<
"XOPeNDAP-Server: " << version.c_str() <<
CRLF ;
936 const time_t t = time(0);
938 strm <<
"Cache-Control: no-cache" <<
CRLF ;
952 fprintf(out,
"HTTP/1.0 304 NOT MODIFIED%s",
CRLF) ;
953 const time_t t = time(0);
968 strm <<
"HTTP/1.0 304 NOT MODIFIED" <<
CRLF ;
969 const time_t t = time(0);
985 ifstream ifs((name +
".ovr").c_str());
992 ifs.getline(tmp, 255);
1014 char *s = fgets(tmp, 255, in);
1015 if (s && strncmp(s,
CRLF, 2) == 0)
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)
void read_multipart_headers(FILE *in, const string &content_type, const ObjectType object_type, const string &cid)
ObjectType
The type of object in the stream coming from the data server.
string cid_to_header_value(const string &cid)
bool found_override(string name, string &doc)
void parse_mime_header(const string &header, string &name, string &value)
void set_mime_binary(ostream &strm, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
ObjectType get_description_type(const string &value)
bool remove_mime_header(FILE *in)
Read and discard the MIME header of the stream in.
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_text(ostream &strm, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
string get_next_mime_header(FILE *in)
string read_multipart_boundary(FILE *in, const string &boundary)
string rfc822_date(const time_t t)
void set_mime_error(ostream &strm, int code, const string &reason, const string &version)
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, const string &ver, EncodingType enc, const time_t last_modified)
void set_mime_multipart(ostream &strm, const string &boundary, const string &start, ObjectType type, const string &version, EncodingType enc, const time_t last_modified)
EncodingType
The type of encoding used on the current stream.
A class for error processing.
#define DAP_PROTOCOL_VERSION
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.