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 22703 2010-05-11 18:10:01Z 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 and DODSFilter.cc 00087 00088 using namespace std; 00089 00090 namespace libdap { 00091 00092 static const int TimLen = 26; // length of string from asctime() 00093 static const int CLUMP_SIZE = 1024; // size of clumps to new in fmakeword() 00094 00108 bool 00109 do_version(const string &script_ver, const string &dataset_ver) 00110 { 00111 fprintf(stdout, "HTTP/1.0 200 OK%s", CRLF) ; 00112 fprintf(stdout, "XDODS-Server: %s%s", DVR, CRLF) ; 00113 fprintf(stdout, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00114 fprintf(stdout, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00115 fprintf(stdout, "Content-Type: text/plain%s", CRLF) ; 00116 fprintf(stdout, CRLF) ; 00117 00118 fprintf(stdout, "Core software version: %s%s", DVR, CRLF) ; 00119 00120 if (script_ver != "") 00121 fprintf(stdout, "Server Script Revision: %s%s", script_ver.c_str(), CRLF) ; 00122 00123 if (dataset_ver != "") 00124 fprintf(stdout, "Dataset version: %s%s", dataset_ver.c_str(), CRLF) ; 00125 00126 fflush(stdout) ; // Not sure this is needed. jhrg 12/23/05 00127 00128 return true; 00129 } 00130 00140 void 00141 ErrMsgT(const string &Msgt) 00142 { 00143 time_t TimBin; 00144 char TimStr[TimLen]; 00145 00146 if (time(&TimBin) == (time_t) - 1) 00147 strncpy(TimStr, "time() error ", TimLen-1); 00148 else { 00149 strncpy(TimStr, ctime(&TimBin), TimLen-1); 00150 TimStr[TimLen - 2] = '\0'; // overwrite the \n 00151 } 00152 00153 cerr << "[" << TimStr << "] DAP server error: " << Msgt << endl; 00154 } 00155 00156 // Given a pathname, return just the filename component with any extension 00157 // removed. The new string resides in newly allocated memory; the caller must 00158 // delete it when done using the filename. 00159 // Originally from the netcdf distribution (ver 2.3.2). 00160 // 00161 // *** Change to string class argument and return type. jhrg 00162 // *** Changed so it also removes the#path#of#the#file# from decompressed 00163 // files. rph. 00164 // Returns: A filename, with path and extension information removed. If 00165 // memory for the new name cannot be allocated, does not return! 00166 00177 string 00178 name_path(const string &path) 00179 { 00180 if (path == "") 00181 return string(""); 00182 00183 string::size_type delim = path.find_last_of(FILE_DELIMITER); 00184 string::size_type pound = path.find_last_of("#"); 00185 string new_path; 00186 00187 if (pound != string::npos) 00188 new_path = path.substr(pound + 1); 00189 else 00190 new_path = path.substr(delim + 1); 00191 00192 return new_path; 00193 } 00194 00195 // Return a MIME rfc-822 date. The grammar for this is: 00196 // date-time = [ day "," ] date time ; dd mm yy 00197 // ; hh:mm:ss zzz 00198 // 00199 // day = "Mon" / "Tue" / "Wed" / "Thu" 00200 // / "Fri" / "Sat" / "Sun" 00201 // 00202 // date = 1*2DIGIT month 2DIGIT ; day month year 00203 // ; e.g. 20 Jun 82 00204 // NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg 00205 // 00206 // month = "Jan" / "Feb" / "Mar" / "Apr" 00207 // / "May" / "Jun" / "Jul" / "Aug" 00208 // / "Sep" / "Oct" / "Nov" / "Dec" 00209 // 00210 // time = hour zone ; ANSI and Military 00211 // 00212 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] 00213 // ; 00:00:00 - 23:59:59 00214 // 00215 // zone = "UT" / "GMT" ; Universal Time 00216 // ; North American : UT 00217 // / "EST" / "EDT" ; Eastern: - 5/ - 4 00218 // / "CST" / "CDT" ; Central: - 6/ - 5 00219 // / "MST" / "MDT" ; Mountain: - 7/ - 6 00220 // / "PST" / "PDT" ; Pacific: - 8/ - 7 00221 // / 1ALPHA ; Military: Z = UT; 00222 // ; A:-1; (J not used) 00223 // ; M:-12; N:+1; Y:+12 00224 // / ( ("+" / "-") 4DIGIT ) ; Local differential 00225 // ; hours+min. (HHMM) 00226 00227 static const char *days[] = 00228 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 00229 }; 00230 static const char *months[] = 00231 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 00232 "Aug", "Sep", "Oct", "Nov", "Dec" 00233 }; 00234 00235 #ifdef _MSC_VER 00236 #define snprintf sprintf_s 00237 #endif 00238 00246 string 00247 rfc822_date(const time_t t) 00248 { 00249 struct tm *stm = gmtime(&t); 00250 char d[256]; 00251 00252 snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday], 00253 stm->tm_mday, months[stm->tm_mon], 00254 1900 + stm->tm_year, 00255 stm->tm_hour, stm->tm_min, stm->tm_sec); 00256 d[255] = '\0'; 00257 return string(d); 00258 } 00259 00265 time_t 00266 last_modified_time(const string &name) 00267 { 00268 struct stat m; 00269 00270 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode)) 00271 return m.st_mtime; 00272 else 00273 return time(0); 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 00374 void 00375 set_mime_text(FILE *out, ObjectType type, const string &ver, 00376 EncodingType enc, const time_t last_modified) 00377 { 00378 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00379 if (ver == "") { 00380 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00381 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00382 } 00383 else { 00384 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00385 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00386 } 00387 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00388 00389 const time_t t = time(0); 00390 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00391 00392 fprintf(out, "Last-Modified: ") ; 00393 if (last_modified > 0) 00394 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00395 else 00396 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00397 00398 if (type == dap4_ddx) 00399 fprintf(out, "Content-Type: text/xml%s", CRLF) ; 00400 else 00401 fprintf(out, "Content-Type: text/plain%s", CRLF) ; 00402 00403 // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616. 00404 // jhrg 12/23/05 00405 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00406 if (type == dods_error) // don't cache our error responses. 00407 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00408 // Don't write a Content-Encoding header for x-plain since that breaks 00409 // Netscape on NT. jhrg 3/23/97 00410 if (enc != x_plain) 00411 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00412 fprintf(out, CRLF) ; 00413 } 00414 #endif 00415 00428 void 00429 set_mime_text(ostream &strm, ObjectType type, const string &ver, 00430 EncodingType enc, const time_t last_modified) 00431 { 00432 strm << "HTTP/1.0 200 OK" << CRLF ; 00433 if (ver == "") { 00434 strm << "XDODS-Server: " << DVR << CRLF ; 00435 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00436 } 00437 else { 00438 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00439 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00440 } 00441 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00442 00443 const time_t t = time(0); 00444 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00445 00446 strm << "Last-Modified: " ; 00447 if (last_modified > 0) 00448 strm << rfc822_date(last_modified).c_str() << CRLF ; 00449 else 00450 strm << rfc822_date(t).c_str() << CRLF ; 00451 00452 if (type == dap4_ddx) 00453 strm << "Content-Type: text/xml" << CRLF ; 00454 else 00455 strm << "Content-Type: text/plain" << CRLF ; 00456 00457 // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616. 00458 // jhrg 12/23/05 00459 strm << "Content-Description: " << descrip[type] << CRLF ; 00460 if (type == dods_error) // don't cache our error responses. 00461 strm << "Cache-Control: no-cache" << CRLF ; 00462 // Don't write a Content-Encoding header for x-plain since that breaks 00463 // Netscape on NT. jhrg 3/23/97 00464 if (enc != x_plain) 00465 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00466 strm << CRLF ; 00467 } 00468 00469 #if FILE_METHODS 00470 00480 void 00481 set_mime_html(FILE *out, ObjectType type, const string &ver, 00482 EncodingType enc, const time_t last_modified) 00483 { 00484 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00485 if (ver == "") { 00486 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00487 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00488 } 00489 else { 00490 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00491 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00492 } 00493 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00494 00495 const time_t t = time(0); 00496 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00497 00498 fprintf(out, "Last-Modified: ") ; 00499 if (last_modified > 0) 00500 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00501 else 00502 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00503 00504 fprintf(out, "Content-type: text/html%s", CRLF) ; 00505 // See note above about Content-Description header. jhrg 12/23/05 00506 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00507 if (type == dods_error) // don't cache our error responses. 00508 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00509 // Don't write a Content-Encoding header for x-plain since that breaks 00510 // Netscape on NT. jhrg 3/23/97 00511 if (enc != x_plain) 00512 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00513 fprintf(out, CRLF) ; 00514 } 00515 #endif 00516 00527 void 00528 set_mime_html(ostream &strm, ObjectType type, const string &ver, 00529 EncodingType enc, const time_t last_modified) 00530 { 00531 strm << "HTTP/1.0 200 OK" << CRLF ; 00532 if (ver == "") { 00533 strm << "XDODS-Server: " << DVR << CRLF ; 00534 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00535 } 00536 else { 00537 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00538 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00539 } 00540 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00541 00542 const time_t t = time(0); 00543 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00544 00545 strm << "Last-Modified: " ; 00546 if (last_modified > 0) 00547 strm << rfc822_date(last_modified).c_str() << CRLF ; 00548 else 00549 strm << rfc822_date(t).c_str() << CRLF ; 00550 00551 strm << "Content-type: text/html" << CRLF ; 00552 // See note above about Content-Description header. jhrg 12/23/05 00553 strm << "Content-Description: " << descrip[type] << CRLF ; 00554 if (type == dods_error) // don't cache our error responses. 00555 strm << "Cache-Control: no-cache" << CRLF ; 00556 // Don't write a Content-Encoding header for x-plain since that breaks 00557 // Netscape on NT. jhrg 3/23/97 00558 if (enc != x_plain) 00559 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00560 strm << CRLF ; 00561 } 00562 00563 #if FILE_METHODS 00564 00577 void 00578 set_mime_binary(FILE *out, ObjectType type, const string &ver, 00579 EncodingType enc, const time_t last_modified) 00580 { 00581 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ; 00582 if (ver == "") { 00583 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00584 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00585 } 00586 else { 00587 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ; 00588 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ; 00589 } 00590 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00591 00592 const time_t t = time(0); 00593 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00594 00595 fprintf(out, "Last-Modified: ") ; 00596 if (last_modified > 0) 00597 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ; 00598 else 00599 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ; 00600 00601 fprintf(out, "Content-Type: application/octet-stream%s", CRLF) ; 00602 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ; 00603 if (enc != x_plain) 00604 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ; 00605 00606 fprintf(out, CRLF) ; 00607 } 00608 #endif 00609 00623 void 00624 set_mime_binary(ostream &strm, ObjectType type, const string &ver, 00625 EncodingType enc, const time_t last_modified) 00626 { 00627 strm << "HTTP/1.0 200 OK" << CRLF ; 00628 if (ver == "") { 00629 strm << "XDODS-Server: " << DVR << CRLF ; 00630 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00631 } 00632 else { 00633 strm << "XDODS-Server: " << ver.c_str() << CRLF ; 00634 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ; 00635 } 00636 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00637 00638 const time_t t = time(0); 00639 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00640 00641 strm << "Last-Modified: " ; 00642 if (last_modified > 0) 00643 strm << rfc822_date(last_modified).c_str() << CRLF ; 00644 else 00645 strm << rfc822_date(t).c_str() << CRLF ; 00646 00647 strm << "Content-Type: application/octet-stream" << CRLF ; 00648 strm << "Content-Description: " << descrip[type] << CRLF ; 00649 if (enc != x_plain) 00650 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00651 00652 strm << CRLF ; 00653 } 00654 00655 void set_mime_multipart(ostream &strm, const string &boundary, 00656 const string &start, ObjectType type, 00657 const string &version, EncodingType enc, 00658 const time_t last_modified) 00659 { 00660 strm << "HTTP/1.0 200 OK" << CRLF ; 00661 if (version == "") { 00662 strm << "XDODS-Server: " << DVR << CRLF ; 00663 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00664 } 00665 else { 00666 strm << "XDODS-Server: " << version.c_str() << CRLF ; 00667 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ; 00668 } 00669 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00670 00671 const time_t t = time(0); 00672 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00673 00674 strm << "Last-Modified: " ; 00675 if (last_modified > 0) 00676 strm << rfc822_date(last_modified).c_str() << CRLF ; 00677 else 00678 strm << rfc822_date(t).c_str() << CRLF ; 00679 00680 strm << "Content-Type: Multipart/Related; boundary=" << boundary 00681 << "; start=\"<" << start << ">\"; type=\"Text/xml\"" << CRLF ; 00682 strm << "Content-Description: " << descrip[type] << CRLF ; 00683 if (enc != x_plain) 00684 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00685 00686 strm << CRLF ; 00687 } 00688 00689 void set_mime_ddx_boundary(ostream &strm, const string &boundary, 00690 const string &cid, ObjectType type, EncodingType enc) 00691 { 00692 strm << "--" << boundary << CRLF; 00693 strm << "Content-Type: Text/xml; charset=iso-8859-1" << CRLF; 00694 strm << "Content-Id: <" << cid << ">" << CRLF; 00695 strm << "Content-Description: " << descrip[type] << CRLF ; 00696 if (enc != x_plain) 00697 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00698 00699 strm << CRLF; 00700 } 00701 00702 void set_mime_data_boundary(ostream &strm, const string &boundary, 00703 const string &cid, ObjectType type, EncodingType enc) 00704 { 00705 strm << "--" << boundary << CRLF; 00706 strm << "Content-Type: application/octet-stream" << CRLF; 00707 strm << "Content-Id: <" << cid << ">" << CRLF; 00708 strm << "Content-Description: " << descrip[type] << CRLF ; 00709 if (enc != x_plain) 00710 strm << "Content-Encoding: " << encoding[enc] << CRLF ; 00711 00712 strm << CRLF; 00713 } 00714 00715 const size_t line_length = 1024; 00716 00730 string get_next_mime_header(FILE *in) 00731 { 00732 // Get the header line and strip \r\n. Some headers end with just \n. 00733 // If a blank line is found, return an empty string. 00734 char line[line_length]; 00735 while (!feof(in)) { 00736 if (fgets(line, line_length, in) 00737 && (strncmp(line, CRLF, 2) == 0 || line[0] == '\n')) 00738 return ""; 00739 else { 00740 size_t slen = min(strlen(line), line_length); // Never > line_length 00741 line[slen - 1] = '\0'; // remove the newline 00742 if (line[slen - 2] == '\r') // ...and the preceding carriage return 00743 line[slen - 2] = '\0'; 00744 return string(line); 00745 } 00746 } 00747 00748 throw Error("I expected to find a MIME header, but got EOF instead."); 00749 } 00750 00758 void parse_mime_header(const string &header, string &name, string &value) 00759 { 00760 istringstream iss(header); 00761 // Set downcase 00762 char s[line_length]; 00763 iss.getline(s, 1023, ':'); 00764 name = s; 00765 00766 iss.ignore(1023, ' '); 00767 iss.getline(s, 1023); 00768 value = s; 00769 00770 downcase(name); 00771 downcase(value); 00772 } 00773 00781 bool is_boundary(const char *line, const string &boundary) 00782 { 00783 if (!(line[0] == '-' && line[1] == '-')) 00784 return false; 00785 else { 00786 return strncmp(line, boundary.c_str(), boundary.length()) == 0; 00787 } 00788 } 00789 00798 string read_multipart_boundary(FILE *in, const string &boundary) 00799 { 00800 string boundary_line = get_next_mime_header(in); 00801 // If the caller passed in a value for the boundary, test for that value, 00802 // else just see that this line starts with '--'. 00803 // The value of 'boundary_line' is returned by this function. 00804 if ((!boundary.empty() && is_boundary(boundary_line.c_str(), boundary)) 00805 || boundary_line.find("--") != 0) 00806 throw Error( 00807 "The DAP4 data response document is broken - missing or malformed boundary."); 00808 00809 return boundary_line; 00810 } 00811 00832 void read_multipart_headers(FILE *in, const string &content_type, 00833 const ObjectType object_type, const string &cid) 00834 { 00835 bool ct = false, cd = false, ci = false; 00836 00837 string header = get_next_mime_header(in); 00838 while (!header.empty()) { 00839 string name, value; 00840 parse_mime_header(header, name, value); 00841 00842 if (name =="content-type") { 00843 ct = true; 00844 if (value.find(content_type) == string::npos) 00845 throw Error("Content-Type for this part of a DAP4 data response must be " + content_type + "."); 00846 } 00847 else if (name == "content-description") { 00848 cd = true; 00849 if (get_description_type(value) != object_type) 00850 throw Error("Content-Description for this part of a DAP4 data response must be dap4-ddx or dap4-data-ddx"); 00851 } 00852 else if (name == "content-id") { 00853 ci = true; 00854 if (!cid.empty() && value != cid) 00855 throw Error("Content-Id mismatch. Expected: " + cid 00856 + ", but got: " + value); 00857 } 00858 00859 header = get_next_mime_header(in); 00860 } 00861 00862 if (!(ct && cd && ci)) 00863 throw Error("The DAP4 data response document is broken - missing header."); 00864 } 00872 string cid_to_header_value(const string &cid) 00873 { 00874 string::size_type offset = cid.find("cid:"); 00875 if (offset != 0) 00876 throw Error("expected CID to start with 'cid:'"); 00877 00878 string value = "<"; 00879 value.append(cid.substr(offset + 4)); 00880 value.append(">"); 00881 downcase(value); 00882 00883 return value; 00884 } 00885 00886 #if FILE_METHODS 00887 00893 void 00894 set_mime_error(FILE *out, int code, const string &reason, 00895 const string &version) 00896 { 00897 fprintf(out, "HTTP/1.0 %d %s%s", code, reason.c_str(), CRLF) ; 00898 if (version == "") { 00899 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ; 00900 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ; 00901 } 00902 else { 00903 fprintf(out, "XDODS-Server: %s%s", version.c_str(), CRLF) ; 00904 fprintf(out, "XOPeNDAP-Server: %s%s", version.c_str(), CRLF) ; 00905 } 00906 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ; 00907 00908 const time_t t = time(0); 00909 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00910 fprintf(out, "Cache-Control: no-cache%s", CRLF) ; 00911 fprintf(out, CRLF) ; 00912 } 00913 #endif 00914 00921 void 00922 set_mime_error(ostream &strm, int code, const string &reason, 00923 const string &version) 00924 { 00925 strm << "HTTP/1.0 " << code << " " << reason.c_str() << CRLF ; 00926 if (version == "") { 00927 strm << "XDODS-Server: " << DVR << CRLF ; 00928 strm << "XOPeNDAP-Server: " << DVR << CRLF ; 00929 } 00930 else { 00931 strm << "XDODS-Server: " << version.c_str() << CRLF ; 00932 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ; 00933 } 00934 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ; 00935 00936 const time_t t = time(0); 00937 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00938 strm << "Cache-Control: no-cache" << CRLF ; 00939 strm << CRLF ; 00940 } 00941 00942 #if FILE_METHODS 00943 00949 void 00950 set_mime_not_modified(FILE *out) 00951 { 00952 fprintf(out, "HTTP/1.0 304 NOT MODIFIED%s", CRLF) ; 00953 const time_t t = time(0); 00954 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ; 00955 fprintf(out, CRLF) ; 00956 } 00957 #endif 00958 00965 void 00966 set_mime_not_modified(ostream &strm) 00967 { 00968 strm << "HTTP/1.0 304 NOT MODIFIED" << CRLF ; 00969 const time_t t = time(0); 00970 strm << "Date: " << rfc822_date(t).c_str() << CRLF ; 00971 strm << CRLF ; 00972 } 00973 00982 bool 00983 found_override(string name, string &doc) 00984 { 00985 ifstream ifs((name + ".ovr").c_str()); 00986 if (!ifs) 00987 return false; 00988 00989 char tmp[256]; 00990 doc = ""; 00991 while (!ifs.eof()) { 00992 ifs.getline(tmp, 255); 00993 strcat(tmp, "\n"); 00994 doc += tmp; 00995 } 00996 00997 ifs.close(); 00998 return true; 00999 } 01000 01009 bool 01010 remove_mime_header(FILE *in) 01011 { 01012 char tmp[256]; 01013 while (!feof(in)) { 01014 char *s = fgets(tmp, 255, in); 01015 if (s && strncmp(s, CRLF, 2) == 0) 01016 return true; 01017 } 01018 01019 return false; 01020 } 01021 01022 } // namespace libdap 01023