cgi_util.cc

Go to the documentation of this file.
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 
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>    // for access
00059 #include <sys/wait.h>
00060 #else
00061 #include <io.h>
00062 #include <fcntl.h>
00063 #include <process.h>
00064 // Win32 does not define this. 08/21/02 jhrg
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"  // This supplies flush_stream for WIN32.
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 // ...not using a const string here to avoid global objects. jhrg 12/23/05
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; // length of string from asctime()
00092 static const int CLUMP_SIZE = 1024; // size of clumps to new in fmakeword()
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) ;            // Not sure this is needed. jhrg 12/23/05
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 // Given a pathname to a datafile, take that pathname apart and look for an
00222 // ancillary file that describes a group of datafiles of which this datafile
00223 // is a member. Assume that groups follow a simple naming convention where
00224 // files use either leading or trailing digits and a common basename to name
00225 // group members. For example, 00stuff.hdf, 01stuff.hdf, 02stuff.hdf, ..., is
00226 // a group and is has `stuff' as its basename.
00227 
00241 string
00242 find_group_ancillary_file(const string &name, const string &ext)
00243 {
00244     // Given /usr/local/data/stuff.01.nc
00245     // pathname = /usr/local/data, filename = stuff.01.nc and
00246     // rootname = stuff.01
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     // Instead of using regexs, scan the filename for leading and then
00253     // trailing digits.
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         // We want: new_name = dirname + "/" + <base> + ext but without
00262         // creating a bunch of temp objects.
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         // I used reverse iters to scan rootname backwards. To avoid
00282         // reversing the fragment between end_riter and riter, pass append
00283         // regular iters obtained using reverse_iterator::base(). See Meyers
00284         // p. 123. 1/22/2002 jhrg
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     // If we're here either the file does not begin with leading digits or a
00294     // template made by removing those digits was not found.
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'; // overwrite the \n
00319     }
00320     
00321 #if 0
00322         // This was removed because writing these values out 'leaks' system information.
00323         // Since we're not going to write out the script or host, I also removed the 
00324         // calls to getenv(). jhrg 8/7/2007
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 // Given a pathname, return just the filename component with any extension
00337 // removed. The new string resides in newly allocated memory; the caller must
00338 // delete it when done using the filename.
00339 // Originally from the netcdf distribution (ver 2.3.2).
00340 //
00341 // *** Change to string class argument and return type. jhrg
00342 // *** Changed so it also removes the#path#of#the#file# from decompressed
00343 //     files.  rph.
00344 // Returns: A filename, with path and extension information removed. If
00345 // memory for the new name cannot be allocated, does not return!
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 // Return a MIME rfc-822 date. The grammar for this is:
00376 //       date-time   =  [ day "," ] date time        ; dd mm yy
00377 //                                                   ;  hh:mm:ss zzz
00378 //
00379 //       day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
00380 //                   /  "Fri"  / "Sat" /  "Sun"
00381 //
00382 //       date        =  1*2DIGIT month 2DIGIT        ; day month year
00383 //                                                   ;  e.g. 20 Jun 82
00384 //                   NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg
00385 //
00386 //       month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
00387 //                   /  "May"  /  "Jun" /  "Jul"  /  "Aug"
00388 //                   /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
00389 //
00390 //       time        =  hour zone                    ; ANSI and Military
00391 //
00392 //       hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
00393 //                                                   ; 00:00:00 - 23:59:59
00394 //
00395 //       zone        =  "UT"  / "GMT"                ; Universal Time
00396 //                                                   ; North American : UT
00397 //                   /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
00398 //                   /  "CST" / "CDT"                ;  Central:  - 6/ - 5
00399 //                   /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
00400 //                   /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
00401 //                   /  1ALPHA                       ; Military: Z = UT;
00402 //                                                   ;  A:-1; (J not used)
00403 //                                                   ;  M:-12; N:+1; Y:+12
00404 //                   / ( ("+" / "-") 4DIGIT )        ; Local differential
00405 //                                                   ;  hours+min. (HHMM)
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 // Send string to set the transfer (mime) type and server version
00457 // Note that the content description filed is used to indicate whether valid
00458 // information of an error message is contained in the document and the
00459 // content-encoding field is used to indicate whether the data is compressed.
00460 // If the data stream is to be compressed, arrange for a compression output
00461 // filter so that all information sent after the header will be compressed.
00462 //
00463 // Returns: false if the compression output filter was to be used but could
00464 // not be started, true otherwise.
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     // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
00516     // jhrg 12/23/05
00517     fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00518     if (type == dods_error) // don't cache our error responses.
00519         fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00520     // Don't write a Content-Encoding header for x-plain since that breaks
00521     // Netscape on NT. jhrg 3/23/97
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     // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
00569     // jhrg 12/23/05
00570     strm << "Content-Description: " << descrip[type] << CRLF ;
00571     if (type == dods_error) // don't cache our error responses.
00572         strm << "Cache-Control: no-cache" << CRLF ;
00573     // Don't write a Content-Encoding header for x-plain since that breaks
00574     // Netscape on NT. jhrg 3/23/97
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     // See note above about Content-Description header. jhrg 12/23/05
00616     fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00617     if (type == dods_error) // don't cache our error responses.
00618         fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00619     // Don't write a Content-Encoding header for x-plain since that breaks
00620     // Netscape on NT. jhrg 3/23/97
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     // See note above about Content-Description header. jhrg 12/23/05
00662     strm << "Content-Description: " << descrip[type] << CRLF ;
00663     if (type == dods_error) // don't cache our error responses.
00664         strm << "Cache-Control: no-cache" << CRLF ;
00665     // Don't write a Content-Encoding header for x-plain since that breaks
00666     // Netscape on NT. jhrg 3/23/97
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     // Problem: This code is run with the CWD as the CGI-BIN directory but
00937     // the data are in DocumentRoot (and we don't have the pathname of the
00938     // data relative to DocumentRoot). So the only time this will work is
00939     // when the server is in the same directory as the data. See bug 815.
00940     // 10/08/04 jhrg
00941     ifs.open((name + ".html").c_str());
00942 
00943     // If name.html cannot be opened, look for basename.html
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 } // namespace libdap
00962 

Generated on Tue Jun 10 18:00:29 2008 for libdap++ by  doxygen 1.5.4