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 17156 2007-09-21 17:44:27Z jimg $"
00042 };
00043
00044 #include <stdio.h>
00045 #include <stdlib.h>
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 static const int TimLen = 26;
00090 static const int CLUMP_SIZE = 1024;
00091
00105 bool
00106 do_version(const string &script_ver, const string &dataset_ver)
00107 {
00108 fprintf(stdout, "HTTP/1.0 200 OK%s", CRLF) ;
00109 fprintf(stdout, "XDODS-Server: %s%s", DVR, CRLF) ;
00110 fprintf(stdout, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00111 fprintf(stdout, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00112 fprintf(stdout, "Content-Type: text/plain%s", CRLF) ;
00113 fprintf(stdout, CRLF) ;
00114
00115 fprintf(stdout, "Core software version: %s%s", DVR, CRLF) ;
00116
00117 if (script_ver != "")
00118 fprintf(stdout, "Server Script Revision: %s%s", script_ver.c_str(), CRLF) ;
00119
00120 if (dataset_ver != "")
00121 fprintf(stdout, "Dataset version: %s%s", dataset_ver.c_str(), CRLF) ;
00122
00123 fflush(stdout) ;
00124
00125 return true;
00126 }
00127
00172 string
00173 find_ancillary_file(const string &pathname, const string &ext,
00174 const string &dir, const string &file)
00175 {
00176 string::size_type slash = pathname.rfind('/') + 1;
00177 string directory = pathname.substr(0, slash);
00178 string filename = pathname.substr(slash);
00179 string basename = pathname.substr(slash, pathname.rfind('.') - slash);
00180
00181 DBG(cerr << "find ancillary file params: " << pathname << ", " << ext
00182 << ", " << dir << ", " << file << endl);
00183 DBG(cerr << "find ancillary file comp: " << directory << ", " << filename
00184 << ", " << basename << endl);
00185
00186 string dot_ext = "." + ext;
00187
00188 string name = directory + basename + dot_ext;
00189 if (access(name.c_str(), F_OK) == 0)
00190 return name;
00191
00192 name = pathname + dot_ext;
00193 if (access(name.c_str(), F_OK) == 0)
00194 return name;
00195
00196 name = directory + ext;
00197 if (access(name.c_str(), F_OK) == 0)
00198 return name;
00199
00200 name = dir + basename + dot_ext;
00201 if (access(name.c_str(), F_OK) == 0)
00202 return name;
00203
00204 name = directory + file + dot_ext;
00205 if (access(name.c_str(), F_OK) == 0)
00206 return name;
00207
00208 name = dir + file + dot_ext;
00209 if (access(name.c_str(), F_OK) == 0)
00210 return name;
00211
00212 name = dir + ext;
00213 if (access(name.c_str(), F_OK) == 0)
00214 return name;
00215
00216 return "";
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00239 string
00240 find_group_ancillary_file(const string &name, const string &ext)
00241 {
00242
00243
00244
00245 string::size_type slash = name.find_last_of('/');
00246 string dirname = name.substr(0, slash);
00247 string filename = name.substr(slash + 1);
00248 string rootname = filename.substr(0, filename.find_last_of('.'));
00249
00250
00251
00252 string::iterator rootname_iter = rootname.begin();
00253 string::iterator rootname_end_iter = rootname.end();
00254 if (isdigit(*rootname_iter)) {
00255 while (rootname_iter != rootname_end_iter
00256 && isdigit(*++rootname_iter))
00257 ;
00258
00259
00260
00261 string new_name = dirname;
00262 new_name.append("/");
00263 new_name.append(rootname_iter, rootname_end_iter);
00264 new_name.append(ext);
00265 DBG(cerr << "New Name (iter): " << new_name << endl);
00266 if (access(new_name.c_str(), F_OK) == 0) {
00267 return new_name;
00268 }
00269 }
00270
00271 string::reverse_iterator rootname_riter = rootname.rbegin();
00272 string::reverse_iterator rootname_end_riter = rootname.rend();
00273 if (isdigit(*rootname_riter)) {
00274 while (rootname_riter != rootname_end_riter
00275 && isdigit(*++rootname_riter))
00276 ;
00277 string new_name = dirname;
00278 new_name.append("/");
00279
00280
00281
00282
00283 new_name.append(rootname_end_riter.base(), rootname_riter.base());
00284 new_name.append(ext);
00285 DBG(cerr << "New Name (riter): " << new_name << endl);
00286 if (access(new_name.c_str(), F_OK) == 0) {
00287 return new_name;
00288 }
00289 }
00290
00291
00292
00293
00294 return "";
00295 }
00296
00306 void
00307 ErrMsgT(const string &Msgt)
00308 {
00309 time_t TimBin;
00310 char TimStr[TimLen];
00311
00312 if (time(&TimBin) == (time_t) - 1)
00313 strncpy(TimStr, "time() error ", TimLen-1);
00314 else {
00315 strncpy(TimStr, ctime(&TimBin), TimLen-1);
00316 TimStr[TimLen - 2] = '\0';
00317 }
00318
00319 #if 0
00320
00321
00322
00323 const char *host_or_addr = getenv("REMOTE_HOST") ? getenv("REMOTE_HOST") :
00324 getenv("REMOTE_ADDR") ? getenv("REMOTE_ADDR") : "local (a non-CGI run)";
00325 const char *script = getenv("SCRIPT_NAME") ? getenv("SCRIPT_NAME") :
00326 "OPeNDAP server";
00327
00328 cerr << "[" << TimStr << "] CGI: " << script << " failed for "
00329 << host_or_addr << ": " << Msgt << endl;
00330 #endif
00331 cerr << "[" << TimStr << "] DAP server error: " << Msgt << endl;
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00355 string
00356 name_path(const string &path)
00357 {
00358 if (path == "")
00359 return string("");
00360
00361 string::size_type delim = path.find_last_of(FILE_DELIMITER);
00362 string::size_type pound = path.find_last_of("#");
00363 string new_path;
00364
00365 if (pound != string::npos)
00366 new_path = path.substr(pound + 1);
00367 else
00368 new_path = path.substr(delim + 1);
00369
00370 return new_path;
00371 }
00372
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 static const char *days[] =
00406 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00407 };
00408 static const char *months[] =
00409 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
00410 "Aug", "Sep", "Oct", "Nov", "Dec"
00411 };
00412
00421 string
00422 rfc822_date(const time_t t)
00423 {
00424 struct tm *stm = gmtime(&t);
00425 char d[256];
00426
00427 snprintf(d, 255, "%s, %02d %s %4d %02d:%02d:%02d GMT", days[stm->tm_wday],
00428 stm->tm_mday, months[stm->tm_mon],
00429 1900 + stm->tm_year,
00430 stm->tm_hour, stm->tm_min, stm->tm_sec);
00431 d[255] = '\0';
00432 return string(d);
00433 }
00434
00440 time_t
00441 last_modified_time(const string &name)
00442 {
00443 struct stat m;
00444
00445 if (stat(name.c_str(), &m) == 0 && (S_IFREG & m.st_mode))
00446 return m.st_mtime;
00447 else
00448 return time(0);
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 static const char *descrip[] =
00462 {"unknown", "dods_das", "dods_dds", "dods_data",
00463 "dods_error", "web_error", "dap4_ddx"
00464 };
00465 static const char *encoding[] =
00466 {"unknown", "deflate", "x-plain"
00467 };
00468
00481 void
00482 set_mime_text(FILE *out, ObjectType type, const string &ver,
00483 EncodingType enc, const time_t last_modified)
00484 {
00485 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00486 if (ver == "") {
00487 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00488 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00489 }
00490 else {
00491 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00492 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00493 }
00494 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00495
00496 const time_t t = time(0);
00497 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00498
00499 fprintf(out, "Last-Modified: ") ;
00500 if (last_modified > 0)
00501 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00502 else
00503 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00504
00505 if (type == dap4_ddx)
00506 fprintf(out, "Content-Type: text/xml%s", CRLF) ;
00507 else
00508 fprintf(out, "Content-Type: text/plain%s", CRLF) ;
00509
00510
00511
00512 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00513 if (type == dods_error)
00514 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00515
00516
00517 if (enc != x_plain)
00518 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00519 fprintf(out, CRLF) ;
00520 }
00521
00534 void
00535 set_mime_text(ostream &strm, ObjectType type, const string &ver,
00536 EncodingType enc, const time_t last_modified)
00537 {
00538 strm << "HTTP/1.0 200 OK" << CRLF ;
00539 if (ver == "") {
00540 strm << "XDODS-Server: " << DVR << CRLF ;
00541 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00542 }
00543 else {
00544 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00545 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00546 }
00547 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00548
00549 const time_t t = time(0);
00550 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00551
00552 strm << "Last-Modified: " ;
00553 if (last_modified > 0)
00554 strm << rfc822_date(last_modified).c_str() << CRLF ;
00555 else
00556 strm << rfc822_date(t).c_str() << CRLF ;
00557
00558 if (type == dap4_ddx)
00559 strm << "Content-Type: text/xml" << CRLF ;
00560 else
00561 strm << "Content-Type: text/plain" << CRLF ;
00562
00563
00564
00565 strm << "Content-Description: " << descrip[type] << CRLF ;
00566 if (type == dods_error)
00567 strm << "Cache-Control: no-cache" << CRLF ;
00568
00569
00570 if (enc != x_plain)
00571 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00572 strm << CRLF ;
00573 }
00574
00585 void
00586 set_mime_html(FILE *out, ObjectType type, const string &ver,
00587 EncodingType enc, const time_t last_modified)
00588 {
00589 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00590 if (ver == "") {
00591 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00592 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00593 }
00594 else {
00595 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00596 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00597 }
00598 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00599
00600 const time_t t = time(0);
00601 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00602
00603 fprintf(out, "Last-Modified: ") ;
00604 if (last_modified > 0)
00605 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00606 else
00607 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00608
00609 fprintf(out, "Content-type: text/html%s", CRLF) ;
00610
00611 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00612 if (type == dods_error)
00613 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00614
00615
00616 if (enc != x_plain)
00617 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00618 fprintf(out, CRLF) ;
00619 }
00620
00631 void
00632 set_mime_html(ostream &strm, ObjectType type, const string &ver,
00633 EncodingType enc, const time_t last_modified)
00634 {
00635 strm << "HTTP/1.0 200 OK" << CRLF ;
00636 if (ver == "") {
00637 strm << "XDODS-Server: " << DVR << CRLF ;
00638 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00639 }
00640 else {
00641 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00642 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00643 }
00644 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00645
00646 const time_t t = time(0);
00647 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00648
00649 strm << "Last-Modified: " ;
00650 if (last_modified > 0)
00651 strm << rfc822_date(last_modified).c_str() << CRLF ;
00652 else
00653 strm << rfc822_date(t).c_str() << CRLF ;
00654
00655 strm << "Content-type: text/html" << CRLF ;
00656
00657 strm << "Content-Description: " << descrip[type] << CRLF ;
00658 if (type == dods_error)
00659 strm << "Cache-Control: no-cache" << CRLF ;
00660
00661
00662 if (enc != x_plain)
00663 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00664 strm << CRLF ;
00665 }
00666
00680 void
00681 set_mime_binary(FILE *out, ObjectType type, const string &ver,
00682 EncodingType enc, const time_t last_modified)
00683 {
00684 fprintf(out, "HTTP/1.0 200 OK%s", CRLF) ;
00685 if (ver == "") {
00686 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00687 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00688 }
00689 else {
00690 fprintf(out, "XDODS-Server: %s%s", ver.c_str(), CRLF) ;
00691 fprintf(out, "XOPeNDAP-Server: %s%s", ver.c_str(), CRLF) ;
00692 }
00693 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00694
00695 const time_t t = time(0);
00696 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00697
00698 fprintf(out, "Last-Modified: ") ;
00699 if (last_modified > 0)
00700 fprintf(out, "%s%s", rfc822_date(last_modified).c_str(), CRLF) ;
00701 else
00702 fprintf(out, "%s%s", rfc822_date(t).c_str(), CRLF) ;
00703
00704 fprintf(out, "Content-Type: application/octet-stream%s", CRLF) ;
00705 fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00706 if (enc != x_plain)
00707 fprintf(out, "Content-Encoding: %s%s", encoding[enc], CRLF) ;
00708
00709 fprintf(out, CRLF) ;
00710 }
00711
00725 void
00726 set_mime_binary(ostream &strm, ObjectType type, const string &ver,
00727 EncodingType enc, const time_t last_modified)
00728 {
00729 strm << "HTTP/1.0 200 OK" << CRLF ;
00730 if (ver == "") {
00731 strm << "XDODS-Server: " << DVR << CRLF ;
00732 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00733 }
00734 else {
00735 strm << "XDODS-Server: " << ver.c_str() << CRLF ;
00736 strm << "XOPeNDAP-Server: " << ver.c_str() << CRLF ;
00737 }
00738 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00739
00740 const time_t t = time(0);
00741 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00742
00743 strm << "Last-Modified: " ;
00744 if (last_modified > 0)
00745 strm << rfc822_date(last_modified).c_str() << CRLF ;
00746 else
00747 strm << rfc822_date(t).c_str() << CRLF ;
00748
00749 strm << "Content-Type: application/octet-stream" << CRLF ;
00750 strm << "Content-Description: " << descrip[type] << CRLF ;
00751 if (enc != x_plain)
00752 strm << "Content-Encoding: " << encoding[enc] << CRLF ;
00753
00754 strm << CRLF ;
00755 }
00756
00757
00764 void
00765 set_mime_error(FILE *out, int code, const string &reason,
00766 const string &version)
00767 {
00768 fprintf(out, "HTTP/1.0 %d %s%s", code, reason.c_str(), CRLF) ;
00769 if (version == "") {
00770 fprintf(out, "XDODS-Server: %s%s", DVR, CRLF) ;
00771 fprintf(out, "XOPeNDAP-Server: %s%s", DVR, CRLF) ;
00772 }
00773 else {
00774 fprintf(out, "XDODS-Server: %s%s", version.c_str(), CRLF) ;
00775 fprintf(out, "XOPeNDAP-Server: %s%s", version.c_str(), CRLF) ;
00776 }
00777 fprintf(out, "XDAP: %s%s", DAP_PROTOCOL_VERSION, CRLF) ;
00778
00779 const time_t t = time(0);
00780 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00781 fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00782 fprintf(out, CRLF) ;
00783 }
00784
00791 void
00792 set_mime_error(ostream &strm, int code, const string &reason,
00793 const string &version)
00794 {
00795 strm << "HTTP/1.0 " << code << " " << reason.c_str() << CRLF ;
00796 if (version == "") {
00797 strm << "XDODS-Server: " << DVR << CRLF ;
00798 strm << "XOPeNDAP-Server: " << DVR << CRLF ;
00799 }
00800 else {
00801 strm << "XDODS-Server: " << version.c_str() << CRLF ;
00802 strm << "XOPeNDAP-Server: " << version.c_str() << CRLF ;
00803 }
00804 strm << "XDAP: " << DAP_PROTOCOL_VERSION << CRLF ;
00805
00806 const time_t t = time(0);
00807 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00808 strm << "Cache-Control: no-cache" << CRLF ;
00809 strm << CRLF ;
00810 }
00811
00812
00819 void
00820 set_mime_not_modified(FILE *out)
00821 {
00822 fprintf(out, "HTTP/1.0 304 NOT MODIFIED%s", CRLF) ;
00823 const time_t t = time(0);
00824 fprintf(out, "Date: %s%s", rfc822_date(t).c_str(), CRLF) ;
00825 fprintf(out, CRLF) ;
00826 }
00827
00834 void
00835 set_mime_not_modified(ostream &strm)
00836 {
00837 strm << "HTTP/1.0 304 NOT MODIFIED" << CRLF ;
00838 const time_t t = time(0);
00839 strm << "Date: " << rfc822_date(t).c_str() << CRLF ;
00840 strm << CRLF ;
00841 }
00842
00851 bool
00852 found_override(string name, string &doc)
00853 {
00854 ifstream ifs((name + ".ovr").c_str());
00855 if (!ifs)
00856 return false;
00857
00858 char tmp[256];
00859 doc = "";
00860 while (!ifs.eof()) {
00861 ifs.getline(tmp, 255);
00862 strcat(tmp, "\n");
00863 doc += tmp;
00864 }
00865
00866 return true;
00867 }
00868
00877 bool
00878 remove_mime_header(FILE *in)
00879 {
00880 char tmp[256];
00881 while (!feof(in)) {
00882 fgets(tmp, 255, in);
00883 if (strncmp(&tmp[0], CRLF, 2) == 0)
00884 return true;
00885 }
00886
00887 return false;
00888 }
00889
00890
00913 string
00914 get_user_supplied_docs(string name, string cgi)
00915 {
00916 char tmp[256];
00917 ostringstream oss;
00918 ifstream ifs((cgi + ".html").c_str());
00919
00920 if (ifs) {
00921 while (!ifs.eof()) {
00922 ifs.getline(tmp, 255);
00923 oss << tmp << "\n";
00924 }
00925 ifs.close();
00926
00927 oss << "<hr>";
00928 }
00929
00930
00931
00932
00933
00934
00935 ifs.open((name + ".html").c_str());
00936
00937
00938 if (!ifs) {
00939 string new_name = find_group_ancillary_file(name, ".html");
00940 if (new_name != "")
00941 ifs.open(new_name.c_str());
00942 }
00943
00944 if (ifs) {
00945 while (!ifs.eof()) {
00946 ifs.getline(tmp, 255);
00947 oss << tmp << "\n";
00948 }
00949 ifs.close();
00950 }
00951
00952 return oss.str();
00953 }
00954