libdap++
Updated for version 3.8.2
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // Reza Nekovei <rnekovei@intcomm.net> 00010 // 00011 // This library is free software; you can redistribute it and/or 00012 // modify it under the terms of the GNU Lesser General Public 00013 // License as published by the Free Software Foundation; either 00014 // version 2.1 of the License, or (at your option) any later version. 00015 // 00016 // This library is distributed in the hope that it will be useful, 00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 // Lesser General Public License for more details. 00020 // 00021 // You should have received a copy of the GNU Lesser General Public 00022 // License along with this library; if not, write to the Free Software 00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 // 00025 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00026 00027 // (c) COPYRIGHT URI/MIT 1994-2001 00028 // Please read the full copyright statement in the file COPYRIGHT_URI. 00029 // 00030 // Authors: 00031 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00032 // reza Reza Nekovei <rnekovei@intcomm.net> 00033 00034 // A few useful routines which are used in CGI programs. 00035 // 00036 // ReZa 9/30/94 00037 00038 #include "config.h" 00039 #undef FILE_METHODS 00040 00041 static char rcsid[] not_used = 00042 {"$Id: mime_util.cc 24869 2011-08-24 23:17:41Z jimg $" 00043 }; 00044 00045 #include <cstring> 00046 #include <cstdio> 00047 #include <ctype.h> 00048 00049 #ifndef TM_IN_SYS_TIME 00050 #include <time.h> 00051 #else 00052 #include <sys/time.h> 00053 #endif 00054 00055 #include <sys/types.h> 00056 #include <sys/stat.h> 00057 00058 #ifndef WIN32 00059 #include <unistd.h> // for access 00060 #include <sys/wait.h> 00061 #else 00062 #include <io.h> 00063 #include <fcntl.h> 00064 #include <process.h> 00065 // Win32 does not define this. 08/21/02 jhrg 00066 #define F_OK 0 00067 #endif 00068 00069 #include <iostream> 00070 #include <sstream> 00071 #include <fstream> 00072 #include <string> 00073 00074 #include "mime_util.h" 00075 #include "Ancillary.h" 00076 #include "util.h" // This supplies flush_stream for WIN32. 00077 #include "debug.h" 00078 00079 #ifdef WIN32 00080 #define FILE_DELIMITER '\\' 00081 #else // default to unix 00082 #define FILE_DELIMITER '/' 00083 #endif 00084 00085 // ...not using a const string here to avoid global objects. jhrg 12/23/05 00086 #define CRLF "\r\n" // Change here, expr-test.cc, in DODSFilter and ResponseBuilder 00087 00088 using namespace std; 00089 00090 namespace libdap { 00091 00097 time_t 00098 last_modified_time(const string &name) 00099 { 00100 struct stat m; 00101 00102 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode)) 00103 return m.st_mtime; 00104 else 00105 return time(0); 00106 } 00107 // Return a MIME rfc-822 date. The grammar for this is: 00108 // date-time = [ day "," ] date time ; dd mm yy 00109 // ; hh:mm:ss zzz 00110 // 00111 // day = "Mon" / "Tue" / "Wed" / "Thu" 00112 // / "Fri" / "Sat" / "Sun" 00113 // 00114 // date = 1*2DIGIT month 2DIGIT ; day month year 00115 // ; e.g. 20 Jun 82 00116 // NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg 00117 // 00118 // month = "Jan" / "Feb" / "Mar" / "Apr" 00119 // / "May" / "Jun" / "Jul" / "Aug" 00120 // / "Sep" / "Oct" / "Nov" / "Dec" 00121 // 00122 // time = hour zone ; ANSI and Military 00123 // 00124 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] 00125 // ; 00:00:00 - 23:59:59 00126 // 00127 // zone = "UT" / "GMT" ; Universal Time 00128 // ; North American : UT 00129 // / "EST" / "EDT" ; Eastern: - 5/ - 4 00130 // / "CST" / "CDT" ; Central: - 6/ - 5 00131 // / "MST" / "MDT" ; Mountain: - 7/ - 6 00132 // / "PST" / "PDT" ; Pacific: - 8/ - 7 00133 // / 1ALPHA ; Military: Z = UT; 00134 // ; A:-1; (J not used) 00135 // ; M:-12; N:+1; Y:+12 00136 // / ( ("+" / "-") 4DIGIT ) ; Local differential 00137 // ; hours+min. (HHMM) 00138 00139 static const char *days[] = 00140 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 00141 }; 00142 static const char *months[] = 00143 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 00144 "Aug", "Sep", "Oct", "Nov", "Dec" 00145 }; 00146 00147 #ifdef _MSC_VER 00148 #define snprintf sprintf_s 00149 #endif 00150 00158 string 00159 rfc822_date(const time_t t) 00160 { 00161 struct tm *stm = gmtime(&t); 00162 char d[256]; 00163 00164 snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday], 00165 stm->tm_mday, months[stm->tm_mon], 00166 1900 + stm->tm_year, 00167 stm->tm_hour, stm->tm_min, stm->tm_sec); 00168 d[255] = '\0'; 00169 return string(d); 00170 } 00171 00172 static const int TimLen = 26; // length of string from asctime() 00173 static const int CLUMP_SIZE = 1024; // size of clumps to new in fmakeword() 00174 00188 bool 00189 do_version(const string &script_ver, const string &dataset_ver) 00190 { 00191 fprintf(stdout, "HTTP/1.0 200 OK%s", CRLF) ; 00192 fprintf(stdout, "XDODS-Server: %s%s", DVR, CRLF) ; 00193 fprintf(stdout, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00194 fprintf(stdout, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00195 fprintf(stdout, "Content-Type: text/plain%s", CRLF) ; 00196 fprintf(stdout, CRLF) ; 00197 00198 fprintf(stdout, "Core software version: %s%s", DVR, CRLF) ; 00199 00200 if (script_ver != "") 00201 fprintf(stdout, "Server Script Revision: %s%s", script_ver.c_str(), CRLF) ; 00202 00203 if (dataset_ver != "") 00204 fprintf(stdout, "Dataset version: %s%s", dataset_ver.c_str(), CRLF) ; 00205 00206 fflush(stdout) ; // Not sure this is needed. jhrg 12/23/05 00207 00208 return true; 00209 } 00210 00221 void 00222 ErrMsgT(const string &Msgt) 00223 { 00224 time_t TimBin; 00225 char TimStr[TimLen]; 00226 00227 if (time(&TimBin) == (time_t) - 1) 00228 strncpy(TimStr, "time() error ", TimLen-1); 00229 else { 00230 strncpy(TimStr, ctime(&TimBin), TimLen-1); 00231 TimStr[TimLen - 2] = '\0'; // overwrite the \n 00232 } 00233 00234 cerr << "[" << TimStr << "] DAP server error: " << Msgt << endl; 00235 } 00236 00237 // Given a pathname, return just the filename component with any extension 00238 // removed. The new string resides in newly allocated memory; the caller must 00239 // delete it when done using the filename. 00240 // Originally from the netcdf distribution (ver 2.3.2). 00241 // 00242 // *** Change to string class argument and return type. jhrg 00243 // *** Changed so it also removes the#path#of#the#file# from decompressed 00244 // files. rph. 00245 // Returns: A filename, with path and extension information removed. If 00246 // memory for the new name cannot be allocated, does not return! 00247 00258 string 00259 name_path(const string &path) 00260 { 00261 if (path == "") 00262 return string(""); 00263 00264 string::size_type delim = path.find_last_of(FILE_DELIMITER); 00265 string::size_type pound = path.find_last_of("#"); 00266 string new_path; 00267 00268 if (pound != string::npos) 00269 new_path = path.substr(pound + 1); 00270 else 00271 new_path = path.substr(delim + 1); 00272 00273 return new_path; 00274 } 00275 00276 // Send string to set the transfer (mime) type and server version 00277 // Note that the content description filed is used to indicate whether valid 00278 // information of an error message is contained in the document and the 00279 // content-encoding field is used to indicate whether the data is compressed. 00280 // If the data stream is to be compressed, arrange for a compression output 00281 // filter so that all information sent after the header will be compressed. 00282 // 00283 // Returns: false if the compression output filter was to be used but could 00284 // not be started, true otherwise. 00285 00286 static const char *descrip[] = 00287 {"unknown", "dods_das", "dods_dds", "dods_data", 00288 "dods_error", "web_error", "dap4-ddx", "dap4-data", "dap4-error", 00289 "dap4-data-ddx", "dods_ddx" 00290 }; 00291 static const char *encoding[] = 00292 {"unknown", "deflate", "x-plain", "gzip", "binary" 00293 }; 00294 00300 ObjectType 00301 get_type(const string &value) 00302 { 00303 if ((value == "dods_das") | (value == "dods-das")) 00304 return dods_das; 00305 else if ((value == "dods_dds") | (value == "dods-dds")) 00306 return dods_dds; 00307 else if ((value == "dods_data") | (value == "dods-data")) 00308 return dods_data; 00309 else if ((value == "dods_error") | (value == "dods-error")) 00310 return dods_error; 00311 else if ((value == "web_error") | (value == "web-error")) 00312 return web_error; 00313 else if ((value == "dap4_ddx") | (value == "dap4-ddx")) 00314 return dap4_ddx; 00315 else if ((value == "dap4_data") | (value == "dap4-data")) 00316 return dap4_data; 00317 else if ((value == "dap4_error") | (value == "dap4-error")) 00318 return dap4_error; 00319 else if ((value == "dap4_data_ddx") | (value == "dap4-data-ddx")) 00320 return dap4_data_ddx; 00321 else if ((value == "dods_ddx") | (value == "dods-ddx")) 00322 return dods_ddx; 00323 else 00324 return unknown_type; 00325 } 00326 00332 ObjectType 00333 get_description_type(const string &value) 00334 { 00335 if ((value == "dods_das") | (value == "dods-das")) 00336 return dods_das; 00337 else if ((value == "dods_dds") | (value == "dods-dds")) 00338 return dods_dds; 00339 else if ((value == "dods_data") | (value == "dods-data")) 00340 return dods_data; 00341 else if ((value == "dods_error") | (value == "dods-error")) 00342 return dods_error; 00343 else if ((value == "web_error") | (value == "web-error")) 00344 return web_error; 00345 else if ((value == "dods_ddx") | (value == "dods-ddx")) 00346 return dods_ddx; 00347 else if ((value == "dap4_ddx") | (value == "dap4-ddx")) 00348 return dap4_ddx; 00349 else if ((value == "dap4_data") | (value == "dap4-data")) 00350 return dap4_data; 00351 else if ((value == "dap4_error") | (value == "dap4-error")) 00352 return dap4_error; 00353 else if ((value == "dap4_data_ddx") | (value == "dap4-data-ddx")) 00354 return dap4_data_ddx; 00355 else if ((value == "dods_ddx") | (value == "dods-ddx")) 00356 return dods_ddx; 00357 else 00358 return unknown_type; 00359 } 00360 00361 #if FILE_METHODS 00362 00375 void 00376 set_mime_text(FILE *out, ObjectType type, const string &ver, 00377 EncodingType enc, const time_t last_modified) 00378 { 00379 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00380 if (ver == "") { 00381 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00382 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00383 } 00384 else { 00385 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00386 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00387 } 00388 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00389 00390 const time_t t = time(0); 00391 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00392 00393 fprintf(out, "Last-Modified: ") ; 00394 if (last_modified > 0) 00395 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00396 else 00397 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00398 00399 if (type == dap4_ddx) 00400 fprintf(out, "Content-Type: text/xml%s", CRLF) ; 00401 else 00402 fprintf(out, "Content-Type: text/plain%s", CRLF) ; 00403 00404 // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616. 00405 // jhrg 12/23/05 00406 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00407 if (type == dods_error) // don't cache our error responses. 00408 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00409 // Don't write a Content-Encoding header for x-plain since that breaks 00410 // Netscape on NT. jhrg 3/23/97 00411 if (enc != x_plain) 00412 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00413 fprintf(out, CRLF) ; 00414 } 00415 #endif 00416 00430 void 00431 set_mime_text(ostream &strm, ObjectType type, const string &ver, 00432 EncodingType enc, const time_t last_modified) 00433 { 00434 strm << "HTTP/1.0 200 OK" << CRLF ; 00435 if (ver == "") { 00436 strm << "XDODS-Server: " << DVR << CRLF ; 00437 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00438 } 00439 else { 00440 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00441 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00442 } 00443 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00444 00445 const time_t t = time(0); 00446 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00447 00448 strm << "Last-Modified: " ; 00449 if (last_modified > 0) 00450 strm << rfc822_date(last_modified).c_str() << CRLF ; 00451 else 00452 strm << rfc822_date(t).c_str() << CRLF ; 00453 00454 if (type == dap4_ddx) 00455 strm << "Content-Type: text/xml" << CRLF ; 00456 else 00457 strm << "Content-Type: text/plain" << CRLF ; 00458 00459 // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616. 00460 // jhrg 12/23/05 00461 strm << "Content-Description: " << descrip[type] << CRLF ; 00462 if (type == dods_error) // don't cache our error responses. 00463 strm << "Cache-Control: no-cache" << CRLF ; 00464 // Don't write a Content-Encoding header for x-plain since that breaks 00465 // Netscape on NT. jhrg 3/23/97 00466 if (enc != x_plain) 00467 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00468 strm << CRLF ; 00469 } 00470 00471 #if FILE_METHODS 00472 00483 void 00484 set_mime_html(FILE *out, ObjectType type, const string &ver, 00485 EncodingType enc, const time_t last_modified) 00486 { 00487 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00488 if (ver == "") { 00489 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00490 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00491 } 00492 else { 00493 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00494 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00495 } 00496 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00497 00498 const time_t t = time(0); 00499 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00500 00501 fprintf(out, "Last-Modified: ") ; 00502 if (last_modified > 0) 00503 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00504 else 00505 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00506 00507 fprintf(out, "Content-type: text/html%s", CRLF) ; 00508 // See note above about Content-Description header. jhrg 12/23/05 00509 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00510 if (type == dods_error) // don't cache our error responses. 00511 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00512 // Don't write a Content-Encoding header for x-plain since that breaks 00513 // Netscape on NT. jhrg 3/23/97 00514 if (enc != x_plain) 00515 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00516 fprintf(out, CRLF) ; 00517 } 00518 #endif 00519 00531 void 00532 set_mime_html(ostream &strm, ObjectType type, const string &ver, 00533 EncodingType enc, const time_t last_modified) 00534 { 00535 strm << "HTTP/1.0 200 OK" << CRLF ; 00536 if (ver == "") { 00537 strm << "XDODS-Server: " << DVR << CRLF ; 00538 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00539 } 00540 else { 00541 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00542 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00543 } 00544 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00545 00546 const time_t t = time(0); 00547 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00548 00549 strm << "Last-Modified: " ; 00550 if (last_modified > 0) 00551 strm << rfc822_date(last_modified).c_str() << CRLF ; 00552 else 00553 strm << rfc822_date(t).c_str() << CRLF ; 00554 00555 strm << "Content-type: text/html" << CRLF ; 00556 // See note above about Content-Description header. jhrg 12/23/05 00557 strm << "Content-Description: " << descrip[type] << CRLF ; 00558 if (type == dods_error) // don't cache our error responses. 00559 strm << "Cache-Control: no-cache" << CRLF ; 00560 // Don't write a Content-Encoding header for x-plain since that breaks 00561 // Netscape on NT. jhrg 3/23/97 00562 if (enc != x_plain) 00563 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00564 strm << CRLF ; 00565 } 00566 00567 #if FILE_METHODS 00568 00582 void 00583 set_mime_binary(FILE *out, ObjectType type, const string &ver, 00584 EncodingType enc, const time_t last_modified) 00585 { 00586 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00587 if (ver == "") { 00588 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00589 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00590 } 00591 else { 00592 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00593 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00594 } 00595 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00596 00597 const time_t t = time(0); 00598 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00599 00600 fprintf(out, "Last-Modified: ") ; 00601 if (last_modified > 0) 00602 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00603 else 00604 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00605 00606 fprintf(out, "Content-Type: application/octet-stream%s", CRLF) ; 00607 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00608 if (enc != x_plain) 00609 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00610 00611 fprintf(out, CRLF) ; 00612 } 00613 #endif 00614 00629 void 00630 set_mime_binary(ostream &strm, ObjectType type, const string &ver, 00631 EncodingType enc, const time_t last_modified) 00632 { 00633 strm << "HTTP/1.0 200 OK" << CRLF ; 00634 if (ver == "") { 00635 strm << "XDODS-Server: " << DVR << CRLF ; 00636 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00637 } 00638 else { 00639 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00640 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00641 } 00642 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00643 00644 const time_t t = time(0); 00645 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00646 00647 strm << "Last-Modified: " ; 00648 if (last_modified > 0) 00649 strm << rfc822_date(last_modified).c_str() << CRLF ; 00650 else 00651 strm << rfc822_date(t).c_str() << CRLF ; 00652 00653 strm << "Content-Type: application/octet-stream" << CRLF ; 00654 strm << "Content-Description: " << descrip[type] << CRLF ; 00655 if (enc != x_plain) 00656 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00657 00658 strm << CRLF ; 00659 } 00660 00661 void set_mime_multipart(ostream &strm, const string &boundary, 00662 const string &start, ObjectType type, 00663 const string &version, EncodingType enc, 00664 const time_t last_modified) 00665 { 00666 strm << "HTTP/1.0 200 OK" << CRLF ; 00667 if (version == "") { 00668 strm << "XDODS-Server: " << DVR << CRLF ; 00669 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00670 } 00671 else { 00672 strm << "XDODS-Server: " << version.c_str() << CRLF ; 00673 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ; 00674 } 00675 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00676 00677 const time_t t = time(0); 00678 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00679 00680 strm << "Last-Modified: " ; 00681 if (last_modified > 0) 00682 strm << rfc822_date(last_modified).c_str() << CRLF ; 00683 else 00684 strm << rfc822_date(t).c_str() << CRLF ; 00685 00686 strm << "Content-Type: Multipart/Related; boundary=" << boundary 00687 << "; start=\"<" << start << ">\"; type=\"Text/xml\"" << CRLF ; 00688 strm << "Content-Description: " << descrip[type] << CRLF ; 00689 if (enc != x_plain) 00690 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00691 00692 strm << CRLF ; 00693 } 00694 00695 void set_mime_ddx_boundary(ostream &strm, const string &boundary, 00696 const string &cid, ObjectType type, EncodingType enc) 00697 { 00698 strm << "--" << boundary << CRLF; 00699 strm << "Content-Type: Text/xml; charset=iso-8859-1" << CRLF; 00700 strm << "Content-Id: <" << cid << ">" << CRLF; 00701 strm << "Content-Description: " << descrip[type] << CRLF ; 00702 if (enc != x_plain) 00703 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00704 00705 strm << CRLF; 00706 } 00707 00708 void set_mime_data_boundary(ostream &strm, const string &boundary, 00709 const string &cid, ObjectType type, EncodingType enc) 00710 { 00711 strm << "--" << boundary << CRLF; 00712 strm << "Content-Type: application/octet-stream" << CRLF; 00713 strm << "Content-Id: <" << cid << ">" << CRLF; 00714 strm << "Content-Description: " << descrip[type] << CRLF ; 00715 if (enc != x_plain) 00716 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00717 00718 strm << CRLF; 00719 } 00720 00721 const size_t line_length = 1024; 00722 00737 string get_next_mime_header(FILE *in) 00738 { 00739 // Get the header line and strip \r\n. Some headers end with just \n. 00740 // If a blank line is found, return an empty string. 00741 char line[line_length]; 00742 while (!feof(in)) { 00743 if (fgets(line, line_length, in) 00744 && (strncmp(line, CRLF, 2) == 0 || line[0] == '\n')) 00745 return ""; 00746 else { 00747 size_t slen = min(strlen(line), line_length); // Never > line_length 00748 line[slen - 1] = '\0'; // remove the newline 00749 if (line[slen - 2] == '\r') // ...and the preceding carriage return 00750 line[slen - 2] = '\0'; 00751 return string(line); 00752 } 00753 } 00754 00755 throw Error("I expected to find a MIME header, but got EOF instead."); 00756 } 00757 00765 void parse_mime_header(const string &header, string &name, string &value) 00766 { 00767 istringstream iss(header); 00768 // Set downcase 00769 char s[line_length]; 00770 iss.getline(s, 1023, ':'); 00771 name = s; 00772 00773 iss.ignore(1023, ' '); 00774 iss.getline(s, 1023); 00775 value = s; 00776 00777 downcase(name); 00778 downcase(value); 00779 } 00780 00792 bool is_boundary(const char *line, const string &boundary) 00793 { 00794 if (strlen(line) < 2 || !(line[0] == '-' && line[1] == '-')) 00795 return false; 00796 else 00797 return strncmp(line, boundary.c_str(), boundary.length()) == 0; 00798 } 00799 00810 string read_multipart_boundary(FILE *in, const string &boundary) 00811 { 00812 string boundary_line = get_next_mime_header(in); 00813 // If the caller passed in a value for the boundary, test for that value, 00814 // else just see that this line starts with '--'. 00815 // The value of 'boundary_line' is returned by this function. 00816 if ((!boundary.empty() && is_boundary(boundary_line.c_str(), boundary)) 00817 || boundary_line.find("--") != 0) 00818 throw Error( 00819 "The DAP4 data response document is broken - missing or malformed boundary."); 00820 00821 return boundary_line; 00822 } 00823 00844 void read_multipart_headers(FILE *in, const string &content_type, 00845 const ObjectType object_type, const string &cid) 00846 { 00847 bool ct = false, cd = false, ci = false; 00848 00849 string header = get_next_mime_header(in); 00850 while (!header.empty()) { 00851 string name, value; 00852 parse_mime_header(header, name, value); 00853 00854 if (name =="content-type") { 00855 ct = true; 00856 if (value.find(content_type) == string::npos) 00857 throw Error("Content-Type for this part of a DAP4 data response must be " + content_type + "."); 00858 } 00859 else if (name == "content-description") { 00860 cd = true; 00861 if (get_description_type(value) != object_type) 00862 throw Error("Content-Description for this part of a DAP4 data response must be dap4-ddx or dap4-data-ddx"); 00863 } 00864 else if (name == "content-id") { 00865 ci = true; 00866 if (!cid.empty() && value != cid) 00867 throw Error("Content-Id mismatch. Expected: " + cid 00868 + ", but got: " + value); 00869 } 00870 00871 header = get_next_mime_header(in); 00872 } 00873 00874 if (!(ct && cd && ci)) 00875 throw Error("The DAP4 data response document is broken - missing header."); 00876 } 00885 string cid_to_header_value(const string &cid) 00886 { 00887 string::size_type offset = cid.find("cid:"); 00888 if (offset != 0) 00889 throw Error("expected CID to start with 'cid:'"); 00890 00891 string value = "<"; 00892 value.append(cid.substr(offset + 4)); 00893 value.append(">"); 00894 downcase(value); 00895 00896 return value; 00897 } 00898 00899 #if FILE_METHODS 00900 00908 void 00909 set_mime_error(FILE *out, int code, const string &reason, 00910 const string &version) 00911 { 00912 fprintf(out, "HTTP/1.0 %d %s%s", code, reason.c_str(), CRLF) ; 00913 if (version == "") { 00914 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00915 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00916 } 00917 else { 00918 fprintf(out, "XDODS-Server: %s%s", version.c_str(), CRLF) ; 00919 fprintf(out, "XOPeNDAP-Server: %s%s", version.c_str(), CRLF) ; 00920 } 00921 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00922 00923 const time_t t = time(0); 00924 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00925 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00926 fprintf(out, CRLF) ; 00927 } 00928 #endif 00929 00938 void 00939 set_mime_error(ostream &strm, int code, const string &reason, 00940 const string &version) 00941 { 00942 strm << "HTTP/1.0 " << code << " " << reason.c_str() << CRLF ; 00943 if (version == "") { 00944 strm << "XDODS-Server: " << DVR << CRLF ; 00945 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00946 } 00947 else { 00948 strm << "XDODS-Server: " << version.c_str() << CRLF ; 00949 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ; 00950 } 00951 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00952 00953 const time_t t = time(0); 00954 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00955 strm << "Cache-Control: no-cache" << CRLF ; 00956 strm << CRLF ; 00957 } 00958 00959 #if FILE_METHODS 00960 00967 void 00968 set_mime_not_modified(FILE *out) 00969 { 00970 fprintf(out, "HTTP/1.0 304 NOT MODIFIED%s", CRLF) ; 00971 const time_t t = time(0); 00972 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00973 fprintf(out, CRLF) ; 00974 } 00975 #endif 00976 00984 void 00985 set_mime_not_modified(ostream &strm) 00986 { 00987 strm << "HTTP/1.0 304 NOT MODIFIED" << CRLF ; 00988 const time_t t = time(0); 00989 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00990 strm << CRLF ; 00991 } 00992 01002 bool 01003 found_override(string name, string &doc) 01004 { 01005 ifstream ifs((name + ".ovr").c_str()); 01006 if (!ifs) 01007 return false; 01008 01009 char tmp[256]; 01010 doc = ""; 01011 while (!ifs.eof()) { 01012 ifs.getline(tmp, 255); 01013 strcat(tmp, "\n"); 01014 doc += tmp; 01015 } 01016 01017 ifs.close(); 01018 return true; 01019 } 01020 01030 bool 01031 remove_mime_header(FILE *in) 01032 { 01033 char tmp[256]; 01034 while (!feof(in)) { 01035 char *s = fgets(tmp, 255, in); 01036 if (s && strncmp(s, CRLF, 2) == 0) 01037 return true; 01038 } 01039 01040 return false; 01041 } 01042 01043 } // namespace libdap 01044