libdap++  Updated for version 3.8.2
HTTPCache.h
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,2008 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 #ifndef _http_cache_h
00027 #define _http_cache_h
00028 
00029 #include <pthread.h>
00030 
00031 #ifdef WIN32
00032 #include <io.h>   // stat for win32? 09/05/02 jhrg
00033 #endif
00034 
00035 #include <string>
00036 #include <vector>
00037 #include <map>
00038 
00039 #ifndef _http_cache_table_h
00040 #include "HTTPCacheTable.h"
00041 #endif
00042 
00043 #ifndef _error_h
00044 #include "Error.h"
00045 #endif
00046 
00047 #ifndef _internalerr_h
00048 #include "InternalErr.h"
00049 #endif
00050 
00051 #ifndef _debug_h
00052 #include "debug.h"
00053 #endif
00054 
00055 // The private method HTTPCache::write_body() could, at one time, throw
00056 // ResponseTooBig to signal that while writing a response body it was found
00057 // to be bigger than the max_entry_size property. But I bagged that; the
00058 // garbage collection methods remove entries larger than max_entry_size. It
00059 // might be that a really big entry belongs in the cache so long as it
00060 // doesn't push other entries out. 10/07/02 jhrg
00061 #ifndef _response_too_big_err_h
00062 #include "ResponseTooBigErr.h"
00063 #endif
00064 
00065 #ifndef _http_cache_disconnected_mode_h
00066 #include "HTTPCacheDisconnectedMode.h"
00067 #endif
00068 
00069 #ifndef _signal_handler_registered_err_h
00070 #include "SignalHandlerRegisteredErr.h"
00071 #endif
00072 
00073 using namespace std;
00074 
00075 namespace libdap
00076 {
00077 
00078 // This function is exported so the test code can use it too.
00079 bool is_hop_by_hop_header(const string &header);
00080 
00132 class HTTPCache
00133 {
00134 private:
00135     string d_cache_root;
00136     FILE *d_locked_open_file; // Lock for single process use.
00137 
00138     bool d_cache_enabled;
00139     bool d_cache_protected;
00140     CacheDisconnectedMode d_cache_disconnected;
00141     bool d_expire_ignored;
00142     bool d_always_validate;
00143 
00144     unsigned long d_total_size; // How much can we store?
00145     unsigned long d_folder_size; // How much of that is meta data?
00146     unsigned long d_gc_buffer; // How much memory needed as buffer?
00147     unsigned long d_max_entry_size; // Max individual entry size.
00148     int d_default_expiration;
00149 
00150     vector<string> d_cache_control;
00151     // these are values read from a request-directive Cache-Control header.
00152     // Not to be confused with values read from the response or a cached
00153     // response (e.g., CacheEntry has a max_age field, too). These fields are
00154     // set when the set_cache_control method is called.
00155     time_t d_max_age;
00156     time_t d_max_stale;  // -1: not set, 0:any response, >0 max time.
00157     time_t d_min_fresh;
00158 
00159     // Lock non-const methods (also ones that use the STL).
00160     pthread_mutex_t d_cache_mutex;
00161     
00162     HTTPCacheTable *d_http_cache_table;
00163 
00164     // d_open_files is used by the interrupt handler to clean up
00165     vector<string> d_open_files;
00166 
00167     static HTTPCache *_instance;
00168 
00169     friend class HTTPCacheTest; // Unit tests
00170     friend class HTTPCacheInterruptHandler;
00171 
00172     // Private methods
00173     HTTPCache(const HTTPCache &) {
00174         throw InternalErr(__FILE__, __LINE__, "Unimplemented");
00175     }
00176     HTTPCache() {
00177         throw InternalErr(__FILE__, __LINE__, "Unimplemented");
00178     }
00179     HTTPCache &operator=(const HTTPCache &) {
00180         throw InternalErr(__FILE__, __LINE__, "Unimplemented");
00181     }
00182 
00183     HTTPCache(string cache_root, bool force);
00184 
00185     static void delete_instance(); // Run by atexit (hence static)
00186     
00187     void set_cache_root(const string &root = "");
00188     void create_cache_root(const string &cache_root);
00189     
00190     // These will go away when the cache can be used by multiple processes.
00191     bool get_single_user_lock(bool force = false);
00192     void release_single_user_lock();
00193     
00194     bool is_url_in_cache(const string &url);
00195 
00196     // I made these four methods so they could be tested by HTTPCacheTest.
00197     // Otherwise they would be static functions. jhrg 10/01/02
00198     void write_metadata(const string &cachename, const vector<string> &headers);
00199     void read_metadata(const string &cachename, vector<string> &headers);
00200     int write_body(const string &cachename, const FILE *src);
00201     FILE *open_body(const string &cachename);
00202 
00203     bool stopGC() const;
00204     bool startGC() const;
00205 
00206     void perform_garbage_collection();
00207     void too_big_gc();
00208     void expired_gc();
00209     void hits_gc();
00210 
00211 public:
00212     static HTTPCache *instance(const string &cache_root, bool force = false);
00213     virtual ~HTTPCache();
00214 
00215     string get_cache_root() const;
00216 
00217     void set_cache_enabled(bool mode);
00218     bool is_cache_enabled() const;
00219 
00220     void set_cache_disconnected(CacheDisconnectedMode mode);
00221     CacheDisconnectedMode get_cache_disconnected() const;
00222 
00223     void set_expire_ignored(bool mode);
00224     bool is_expire_ignored() const;
00225 
00226     void set_max_size(unsigned long size);
00227     unsigned long get_max_size() const;
00228 
00229     void set_max_entry_size(unsigned long size);
00230     unsigned long get_max_entry_size() const;
00231 
00232     void set_default_expiration(int exp_time);
00233     int get_default_expiration() const;
00234 
00235     void set_always_validate(bool validate);
00236     bool get_always_validate() const;
00237 
00238     void set_cache_control(const vector<string> &cc);
00239     vector<string> get_cache_control();
00240 
00241     void lock_cache_interface() {
00242         DBG(cerr << "Locking interface... ");
00243         LOCK(&d_cache_mutex);
00244         DBGN(cerr << "Done" << endl);
00245     }           
00246     void unlock_cache_interface() {
00247         DBG(cerr << "Unlocking interface... " );
00248         UNLOCK(&d_cache_mutex);
00249         DBGN(cerr << "Done" << endl);
00250     }
00251     
00252     // This must lock for writing
00253     bool cache_response(const string &url, time_t request_time,
00254                         const vector<string> &headers, const FILE *body);
00255     void update_response(const string &url, time_t request_time,
00256                          const vector<string> &headers);
00257 
00258     // This is separate from get_cached_response() because often an invalid
00259     // cache entry just needs a header update. That is best left to the HTTP
00260     // Connection code.
00261     bool is_url_valid(const string &url);
00262     
00263     // Lock these for reading
00264     vector<string> get_conditional_request_headers(const string &url);
00265     FILE *get_cached_response(const string &url, vector<string> &headers,
00266                                                   string &cacheName);
00267     FILE *get_cached_response(const string &url, vector<string> &headers);
00268     FILE *get_cached_response(const string &url);
00269 
00270     void release_cached_response(FILE *response);
00271 
00272     void purge_cache();
00273 };
00274 
00275 } // namespace libdap
00276 
00277 #endif // _http_cache_h