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 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 // 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 static const int TimLen = 26; // length of string from asctime()
00090 static const int CLUMP_SIZE = 1024; // size of clumps to new in fmakeword()
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) ;            // Not sure this is needed. jhrg 12/23/05
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 // Given a pathname to a datafile, take that pathname apart and look for an
00220 // ancillary file that describes a group of datafiles of which this datafile
00221 // is a member. Assume that groups follow a simple naming convention where
00222 // files use either leading or trailing digits and a common basename to name
00223 // group members. For example, 00stuff.hdf, 01stuff.hdf, 02stuff.hdf, ..., is
00224 // a group and is has `stuff' as its basename.
00225 
00239 string
00240 find_group_ancillary_file(const string &name, const string &ext)
00241 {
00242     // Given /usr/local/data/stuff.01.nc
00243     // pathname = /usr/local/data, filename = stuff.01.nc and
00244     // rootname = stuff.01
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     // Instead of using regexs, scan the filename for leading and then
00251     // trailing digits.
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         // We want: new_name = dirname + "/" + <base> + ext but without
00260         // creating a bunch of temp objects.
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         // I used reverse iters to scan rootname backwards. To avoid
00280         // reversing the fragment between end_riter and riter, pass append
00281         // regular iters obtained using reverse_iterator::base(). See Meyers
00282         // p. 123. 1/22/2002 jhrg
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     // If we're here either the file does not begin with leading digits or a
00292     // template made by removing those digits was not found.
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'; // overwrite the \n
00317     }
00318     
00319 #if 0
00320         // This was removed because writing these values out 'leaks' system information.
00321         // Since we're not going to write out the script or host, I also removed the 
00322         // calls to getenv(). jhrg 8/7/2007
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 // Given a pathname, return just the filename component with any extension
00335 // removed. The new string resides in newly allocated memory; the caller must
00336 // delete it when done using the filename.
00337 // Originally from the netcdf distribution (ver 2.3.2).
00338 //
00339 // *** Change to string class argument and return type. jhrg
00340 // *** Changed so it also removes the#path#of#the#file# from decompressed
00341 //     files.  rph.
00342 // Returns: A filename, with path and extension information removed. If
00343 // memory for the new name cannot be allocated, does not return!
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 // Return a MIME rfc-822 date. The grammar for this is:
00374 //       date-time   =  [ day "," ] date time        ; dd mm yy
00375 //                                                   ;  hh:mm:ss zzz
00376 //
00377 //       day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
00378 //                   /  "Fri"  / "Sat" /  "Sun"
00379 //
00380 //       date        =  1*2DIGIT month 2DIGIT        ; day month year
00381 //                                                   ;  e.g. 20 Jun 82
00382 //                   NB: year is 4 digit; see RFC 1123. 11/30/99 jhrg
00383 //
00384 //       month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
00385 //                   /  "May"  /  "Jun" /  "Jul"  /  "Aug"
00386 //                   /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
00387 //
00388 //       time        =  hour zone                    ; ANSI and Military
00389 //
00390 //       hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
00391 //                                                   ; 00:00:00 - 23:59:59
00392 //
00393 //       zone        =  "UT"  / "GMT"                ; Universal Time
00394 //                                                   ; North American : UT
00395 //                   /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
00396 //                   /  "CST" / "CDT"                ;  Central:  - 6/ - 5
00397 //                   /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
00398 //                   /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
00399 //                   /  1ALPHA                       ; Military: Z = UT;
00400 //                                                   ;  A:-1; (J not used)
00401 //                                                   ;  M:-12; N:+1; Y:+12
00402 //                   / ( ("+" / "-") 4DIGIT )        ; Local differential
00403 //                                                   ;  hours+min. (HHMM)
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 // Send string to set the transfer (mime) type and server version
00452 // Note that the content description filed is used to indicate whether valid
00453 // information of an error message is contained in the document and the
00454 // content-encoding field is used to indicate whether the data is compressed.
00455 // If the data stream is to be compressed, arrange for a compression output
00456 // filter so that all information sent after the header will be compressed.
00457 //
00458 // Returns: false if the compression output filter was to be used but could
00459 // not be started, true otherwise.
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     // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
00511     // jhrg 12/23/05
00512     fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00513     if (type == dods_error) // don't cache our error responses.
00514         fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00515     // Don't write a Content-Encoding header for x-plain since that breaks
00516     // Netscape on NT. jhrg 3/23/97
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     // Note that Content-Description is from RFC 2045 (MIME, pt 1), not 2616.
00564     // jhrg 12/23/05
00565     strm << "Content-Description: " << descrip[type] << CRLF ;
00566     if (type == dods_error) // don't cache our error responses.
00567         strm << "Cache-Control: no-cache" << CRLF ;
00568     // Don't write a Content-Encoding header for x-plain since that breaks
00569     // Netscape on NT. jhrg 3/23/97
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     // See note above about Content-Description header. jhrg 12/23/05
00611     fprintf(out, "Content-Description: %s%s", descrip[type], CRLF) ;
00612     if (type == dods_error) // don't cache our error responses.
00613         fprintf(out, "Cache-Control: no-cache%s", CRLF) ;
00614     // Don't write a Content-Encoding header for x-plain since that breaks
00615     // Netscape on NT. jhrg 3/23/97
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     // See note above about Content-Description header. jhrg 12/23/05
00657     strm << "Content-Description: " << descrip[type] << CRLF ;
00658     if (type == dods_error) // don't cache our error responses.
00659         strm << "Cache-Control: no-cache" << CRLF ;
00660     // Don't write a Content-Encoding header for x-plain since that breaks
00661     // Netscape on NT. jhrg 3/23/97
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     // Problem: This code is run with the CWD as the CGI-BIN directory but
00931     // the data are in DocumentRoot (and we don't have the pathname of the
00932     // data relative to DocumentRoot). So the only time this will work is
00933     // when the server is in the same directory as the data. See bug 815.
00934     // 10/08/04 jhrg
00935     ifs.open((name + ".html").c_str());
00936 
00937     // If name.html cannot be opened, look for basename.html
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 

Generated on Wed Jan 2 04:13:16 2008 for libdap++ by  doxygen 1.5.4