00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "config.h"
00039
00040 static char rcsid[] not_used =
00041 {"$Id: cgi_util.cc 18315 2008-03-03 20:14:44Z jimg $"
00042 };
00043
00044 #include <cstring>
00045 #include <cstdio>
00046 #include <ctype.h>
00047
00048 #ifndef TM_IN_SYS_TIME
00049 #include <time.h>
00050 #else
00051 #include <sys/time.h>
00052 #endif
00053
00054 #include <sys/types.h>
00055 #include <sys/stat.h>
00056
00057 #ifndef WIN32
00058 #include <unistd.h>
00059 #include <sys/wait.h>
00060 #else
00061 #include <io.h>
00062 #include <fcntl.h>
00063 #include <process.h>
00064
00065 #define F_OK 0
00066 #endif
00067
00068 #include <iostream>
00069 #include <sstream>
00070 #include <fstream>
00071 #include <string>
00072
00073 #include "cgi_util.h"
00074 #include "util.h"
00075 #include "debug.h"
00076
00077
00078 #ifdef WIN32
00079 #define FILE_DELIMITER '\\'
00080 #else // default to unix
00081 #define FILE_DELIMITER '/'
00082 #endif
00083
00084
00085 #define CRLF "\r\n" // Change here and in expr-test.cc.
00086
00087 using namespace std;
00088
00089 namespace libdap {
00090
00091 static const int TimLen = 26;
00092 static const int CLUMP_SIZE = 1024;
00093
00107 bool
00108 do_version(const string &script_ver, const string &dataset_ver)
00109 {
00110 fprintf(stdout, "HTTP/1.0 200 OK%s", CRLF) ;
00111 fprintf(stdout, "XDODS-Server: %s%s", DVR, CRLF) ;
00112 fprintf(stdout, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00113 fprintf(stdout, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00114 fprintf(stdout, "Content-Type: text/plain%s", CRLF) ;
00115 fprintf(stdout, CRLF) ;
00116
00117 fprintf(stdout, "Core software version: %s%s", DVR, CRLF) ;
00118
00119 if (script_ver != "")
00120 fprintf(stdout, "Server Script Revision: %s%s", script_ver.c_str(), CRLF) ;
00121
00122 if (dataset_ver != "")
00123 fprintf(stdout, "Dataset version: %s%s", dataset_ver.c_str(), CRLF) ;
00124
00125 fflush(stdout) ;
00126
00127 return true;
00128 }
00129
00174 string
00175 find_ancillary_file(const string &pathname, const string &ext,
00176 const string &dir, const string &file)
00177 {
00178 string::size_type slash = pathname.rfind('/') + 1;
00179 string directory = pathname.substr(0, slash);
00180 string filename = pathname.substr(slash);
00181 string basename = pathname.substr(slash, pathname.rfind('.') - slash);
00182
00183 DBG(cerr << "find ancillary file params: " << pathname << ", " << ext
00184 << ", " << dir << ", " << file << endl);
00185 DBG(cerr << "find ancillary file comp: " << directory << ", " << filename
00186 << ", " << basename << endl);
00187
00188 string dot_ext = "." + ext;
00189
00190 string name = directory + basename + dot_ext;
00191 if (access(name.c_str(), F_OK) == 0)
00192 return name;
00193
00194 name = pathname + dot_ext;
00195 if (access(name.c_str(), F_OK) == 0)
00196 return name;
00197
00198 name = directory + ext;
00199 if (access(name.c_str(), F_OK) == 0)
00200 return name;
00201
00202 name = dir + basename + dot_ext;
00203 if (access(name.c_str(), F_OK) == 0)
00204 return name;
00205
00206 name = directory + file + dot_ext;
00207 if (access(name.c_str(), F_OK) == 0)
00208 return name;
00209
00210 name = dir + file + dot_ext;
00211 if (access(name.c_str(), F_OK) == 0)
00212 return name;
00213
00214 name = dir + ext;
00215 if (access(name.c_str(), F_OK) == 0)
00216 return name;
00217
00218 return "";
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00241 string
00242 find_group_ancillary_file(const string &name, const string &ext)
00243 {
00244
00245
00246
00247 string::size_type slash = name.find_last_of('/');
00248 string dirname = name.substr(0, slash);
00249 string filename = name.substr(slash + 1);
00250 string rootname = filename.substr(0, filename.find_last_of('.'));
00251
00252
00253
00254 string::iterator rootname_iter = rootname.begin();
00255 string::iterator rootname_end_iter = rootname.end();
00256 if (isdigit(*rootname_iter)) {
00257 while (rootname_iter != rootname_end_iter
00258 && isdigit(*++rootname_iter))
00259 ;
00260
00261
00262
00263 string new_name = dirname;
00264 new_name.append("/");
00265 new_name.append(rootname_iter, rootname_end_iter);
00266 new_name.append(ext);
00267 DBG(cerr << "New Name (iter): " << new_name << endl);
00268 if (access(new_name.c_str(), F_OK) == 0) {
00269 return new_name;
00270 }
00271 }
00272
00273 string::reverse_iterator rootname_riter = rootname.rbegin();
00274 string::reverse_iterator rootname_end_riter = rootname.rend();
00275 if (isdigit(*rootname_riter)) {
00276 while (rootname_riter != rootname_end_riter
00277 && isdigit(*++rootname_riter))
00278 ;
00279 string new_name = dirname;
00280 new_name.append("/");
00281
00282
00283
00284
00285 new_name.append(rootname_end_riter.base(), rootname_riter.base());
00286 new_name.append(ext);
00287 DBG(cerr << "New Name (riter): " << new_name << endl);
00288 if (access(new_name.c_str(), F_OK) == 0) {
00289 return new_name;
00290 }
00291 }
00292
00293
00294
00295
00296 return "";
00297 }
00298
00308 void
00309 ErrMsgT(const string &Msgt)
00310 {
00311 time_t TimBin;
00312 char TimStr[TimLen];
00313
00314 if (time(&TimBin) == (time_t) - 1)
00315 strncpy(TimStr, "time() error ", TimLen-1);
00316 else {
00317 strncpy(TimStr, ctime(&TimBin), TimLen-1);
00318 TimStr[TimLen - 2] = '\0';
00319 }
00320
00321 #if 0
00322
00323
00324
00325 const char *host_or_addr = getenv("REMOTE_HOST") ? getenv("REMOTE_HOST") :
00326 getenv("REMOTE_ADDR") ? getenv("REMOTE_ADDR") : "local (a non-CGI run)";
00327 const char *script = getenv("SCRIPT_NAME") ? getenv("SCRIPT_NAME") :
00328 "OPeNDAP server";
00329
00330 cerr << "[" << TimStr << "] CGI: " << script << " failed for "
00331 << host_or_addr << ": " << Msgt << endl;
00332 #endif
00333 cerr << "[" << TimStr << "] DAP server error: " << Msgt << endl;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00357 string
00358 name_path(const string &path)
00359 {
00360 if (path == "")
00361 return string("");
00362
00363 string::size_type delim = path.find_last_of(FILE_DELIMITER);
00364 string::size_type pound = path.find_last_of("#");
00365 string new_path;
00366
00367 if (pound != string::npos)
00368 new_path = path.substr(pound + 1);
00369 else
00370 new_path = path.substr(delim + 1);
00371
00372 return new_path;
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 static const char *days[] =
00408 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00409 };
00410 static const char *months[] =
00411 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
00412 "Aug", "Sep", "Oct", "Nov", "Dec"
00413 };
00414
00415 #ifdef _MSC_VER
00416 #define snprintf sprintf_s
00417 #endif
00418
00426 string
00427 rfc822_date(const time_t t)
00428 {
00429 struct tm *stm = gmtime(&t);
00430 char d[256];
00431
00432 snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday],
00433 stm->tm_mday, months[stm->tm_mon],
00434 1900 + stm->tm_year,
00435 stm->tm_hour, stm->tm_min, stm->tm_sec);
00436 d[255] = '\0';
00437 return string(d);
00438 }
00439
00445 time_t
00446 last_modified_time(const string &name)
00447 {
00448 struct stat m;
00449
00450 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
00451 return m.st_mtime;
00452 else
00453 return time(0);
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 static const char *descrip[] =
00467 {"unknown", "dods_das", "dods_dds", "dods_data",
00468 "dods_error", "web_error", "dap4_ddx"
00469 };
00470 static const char *encoding[] =
00471 {"unknown", "deflate", "x-plain"
00472 };
00473
00486 void
00487 set_mime_text(FILE *out, ObjectType type, const string &ver,
00488 EncodingType enc, const time_t last_modified)
00489 {
00490 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00491 if (ver == "") {
00492 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00493 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00494 }
00495 else {
00496 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00497 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00498 }
00499 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00500
00501 const time_t t = time(0);
00502 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00503
00504 fprintf(out, "Last-Modified: ") ;
00505 if (last_modified > 0)
00506 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00507 else
00508 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00509
00510 if (type == dap4_ddx)
00511 fprintf(out, "Content-Type: text/xml%s", CRLF) ;
00512 else
00513 fprintf(out, "Content-Type: text/plain%s", CRLF) ;
00514
00515
00516
00517 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00518 if (type == dods_error)
00519 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00520
00521
00522 if (enc != x_plain)
00523 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00524 fprintf(out, CRLF) ;
00525 }
00526
00539 void
00540 set_mime_text(ostream &strm, ObjectType type, const string &ver,
00541 EncodingType enc, const time_t last_modified)
00542 {
00543 strm << "HTTP/1.0 200 OK" << CRLF ;
00544 if (ver == "") {
00545 strm << "XDODS-Server: " << DVR << CRLF ;
00546 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00547 }
00548 else {
00549 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00550 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00551 }
00552 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00553
00554 const time_t t = time(0);
00555 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00556
00557 strm << "Last-Modified: " ;
00558 if (last_modified > 0)
00559 strm << rfc822_date(last_modified).c_str() << CRLF ;
00560 else
00561 strm << rfc822_date(t).c_str() << CRLF ;
00562
00563 if (type == dap4_ddx)
00564 strm << "Content-Type: text/xml" << CRLF ;
00565 else
00566 strm << "Content-Type: text/plain" << CRLF ;
00567
00568
00569
00570 strm << "Content-Description: " << descrip[type] << CRLF ;
00571 if (type == dods_error)
00572 strm << "Cache-Control: no-cache" << CRLF ;
00573
00574
00575 if (enc != x_plain)
00576 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00577 strm << CRLF ;
00578 }
00579
00590 void
00591 set_mime_html(FILE *out, ObjectType type, const string &ver,
00592 EncodingType enc, const time_t last_modified)
00593 {
00594 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00595 if (ver == "") {
00596 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00597 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00598 }
00599 else {
00600 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00601 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00602 }
00603 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00604
00605 const time_t t = time(0);
00606 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00607
00608 fprintf(out, "Last-Modified: ") ;
00609 if (last_modified > 0)
00610 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00611 else
00612 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00613
00614 fprintf(out, "Content-type: text/html%s", CRLF) ;
00615
00616 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00617 if (type == dods_error)
00618 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00619
00620
00621 if (enc != x_plain)
00622 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00623 fprintf(out, CRLF) ;
00624 }
00625
00636 void
00637 set_mime_html(ostream &strm, ObjectType type, const string &ver,
00638 EncodingType enc, const time_t last_modified)
00639 {
00640 strm << "HTTP/1.0 200 OK" << CRLF ;
00641 if (ver == "") {
00642 strm << "XDODS-Server: " << DVR << CRLF ;
00643 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00644 }
00645 else {
00646 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00647 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00648 }
00649 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00650
00651 const time_t t = time(0);
00652 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00653
00654 strm << "Last-Modified: " ;
00655 if (last_modified > 0)
00656 strm << rfc822_date(last_modified).c_str() << CRLF ;
00657 else
00658 strm << rfc822_date(t).c_str() << CRLF ;
00659
00660 strm << "Content-type: text/html" << CRLF ;
00661
00662 strm << "Content-Description: " << descrip[type] << CRLF ;
00663 if (type == dods_error)
00664 strm << "Cache-Control: no-cache" << CRLF ;
00665
00666
00667 if (enc != x_plain)
00668 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00669 strm << CRLF ;
00670 }
00671
00685 void
00686 set_mime_binary(FILE *out, ObjectType type, const string &ver,
00687 EncodingType enc, const time_t last_modified)
00688 {
00689 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00690 if (ver == "") {
00691 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00692 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00693 }
00694 else {
00695 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00696 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00697 }
00698 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00699
00700 const time_t t = time(0);
00701 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00702
00703 fprintf(out, "Last-Modified: ") ;
00704 if (last_modified > 0)
00705 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00706 else
00707 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00708
00709 fprintf(out, "Content-Type: application/octet-stream%s", CRLF) ;
00710 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00711 if (enc != x_plain)
00712 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00713
00714 fprintf(out, CRLF) ;
00715 }
00716
00730 void
00731 set_mime_binary(ostream &strm, ObjectType type, const string &ver,
00732 EncodingType enc, const time_t last_modified)
00733 {
00734 strm << "HTTP/1.0 200 OK" << CRLF ;
00735 if (ver == "") {
00736 strm << "XDODS-Server: " << DVR << CRLF ;
00737 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00738 }
00739 else {
00740 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00741 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00742 }
00743 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00744
00745 const time_t t = time(0);
00746 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00747
00748 strm << "Last-Modified: " ;
00749 if (last_modified > 0)
00750 strm << rfc822_date(last_modified).c_str() << CRLF ;
00751 else
00752 strm << rfc822_date(t).c_str() << CRLF ;
00753
00754 strm << "Content-Type: application/octet-stream" << CRLF ;
00755 strm << "Content-Description: " << descrip[type] << CRLF ;
00756 if (enc != x_plain)
00757 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00758
00759 strm << CRLF ;
00760 }
00761
00762
00769 void
00770 set_mime_error(FILE *out, int code, const string &reason,
00771 const string &version)
00772 {
00773 fprintf(out, "HTTP/1.0 %d %s%s", code, reason.c_str(), CRLF) ;
00774 if (version == "") {
00775 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00776 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00777 }
00778 else {
00779 fprintf(out, "XDODS-Server: %s%s", version.c_str(), CRLF) ;
00780 fprintf(out, "XOPeNDAP-Server: %s%s", version.c_str(), CRLF) ;
00781 }
00782 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00783
00784 const time_t t = time(0);
00785 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00786 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00787 fprintf(out, CRLF) ;
00788 }
00789
00796 void
00797 set_mime_error(ostream &strm, int code, const string &reason,
00798 const string &version)
00799 {
00800 strm << "HTTP/1.0 " << code << " " << reason.c_str() << CRLF ;
00801 if (version == "") {
00802 strm << "XDODS-Server: " << DVR << CRLF ;
00803 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00804 }
00805 else {
00806 strm << "XDODS-Server: " << version.c_str() << CRLF ;
00807 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ;
00808 }
00809 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00810
00811 const time_t t = time(0);
00812 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00813 strm << "Cache-Control: no-cache" << CRLF ;
00814 strm << CRLF ;
00815 }
00816
00817
00824 void
00825 set_mime_not_modified(FILE *out)
00826 {
00827 fprintf(out, "HTTP/1.0 304 NOT MODIFIED%s", CRLF) ;
00828 const time_t t = time(0);
00829 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00830 fprintf(out, CRLF) ;
00831 }
00832
00839 void
00840 set_mime_not_modified(ostream &strm)
00841 {
00842 strm << "HTTP/1.0 304 NOT MODIFIED" << CRLF ;
00843 const time_t t = time(0);
00844 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00845 strm << CRLF ;
00846 }
00847
00856 bool
00857 found_override(string name, string &doc)
00858 {
00859 ifstream ifs((name + ".ovr").c_str());
00860 if (!ifs)
00861 return false;
00862
00863 char tmp[256];
00864 doc = "";
00865 while (!ifs.eof()) {
00866 ifs.getline(tmp, 255);
00867 strcat(tmp, "\n");
00868 doc += tmp;
00869 }
00870
00871 ifs.close();
00872 return true;
00873 }
00874
00883 bool
00884 remove_mime_header(FILE *in)
00885 {
00886 char tmp[256];
00887 while (!feof(in)) {
00888 fgets(tmp, 255, in);
00889 if (strncmp(&tmp[0], CRLF, 2) == 0)
00890 return true;
00891 }
00892
00893 return false;
00894 }
00895
00896
00919 string
00920 get_user_supplied_docs(string name, string cgi)
00921 {
00922 char tmp[256];
00923 ostringstream oss;
00924 ifstream ifs((cgi + ".html").c_str());
00925
00926 if (ifs) {
00927 while (!ifs.eof()) {
00928 ifs.getline(tmp, 255);
00929 oss << tmp << "\n";
00930 }
00931 ifs.close();
00932
00933 oss << "<hr>";
00934 }
00935
00936
00937
00938
00939
00940
00941 ifs.open((name + ".html").c_str());
00942
00943
00944 if (!ifs) {
00945 string new_name = find_group_ancillary_file(name, ".html");
00946 if (new_name != "")
00947 ifs.open(new_name.c_str());
00948 }
00949
00950 if (ifs) {
00951 while (!ifs.eof()) {
00952 ifs.getline(tmp, 255);
00953 oss << tmp << "\n";
00954 }
00955 ifs.close();
00956 }
00957
00958 return oss.str();
00959 }
00960
00961 }
00962