diff options
-rw-r--r-- | ace/Filecache.cpp | 155 | ||||
-rw-r--r-- | ace/Filecache.h | 109 | ||||
-rw-r--r-- | apps/JAWS/ChangeLog | 8 | ||||
-rw-r--r-- | apps/JAWS/clients/Caching/Makefile | 49 | ||||
-rw-r--r-- | apps/JAWS/clients/Caching/http_client.cpp | 66 | ||||
-rw-r--r-- | apps/JAWS/clients/Caching/http_handler.cpp | 248 | ||||
-rw-r--r-- | apps/JAWS/clients/Caching/http_handler.h | 39 |
7 files changed, 568 insertions, 106 deletions
diff --git a/ace/Filecache.cpp b/ace/Filecache.cpp index 94b9747dd2f..6a2412e3b93 100644 --- a/ace/Filecache.cpp +++ b/ace/Filecache.cpp @@ -27,7 +27,7 @@ static const int WCOPY_FLAGS = O_RDWR | O_CREAT | O_TRUNC; ACE_Filecache *ACE_Filecache::cvf_ = 0; ACE_SYNCH_RW_MUTEX ACE_Filecache::lock_; -// This is how you make data opaque in C++ I'd like to do this with +// This is how you make data opaque in C++. I'd like to do this with // ACE_Filecache_Object too, but Doug would pro'ly kill me. class ACE_Filecache_Singleton { @@ -51,6 +51,111 @@ private: // needed in the future when we remove reliance on copying files. static ACE_Filecache_Singleton cvf_singleton; +class ACE_Filecache_Object + // = TITLE + // Abstraction over a real file. This is what the Virtual + // Filesystem contains. This class is not intended for general + // consumption. Please consult a physician before attempting to + // use this class. +{ +public: + ACE_Filecache_Object (const char *filename); + // Creates a file for reading. + + ACE_Filecache_Object (const char *filename, + int size); + // Creates a file for writing. + + ~ACE_Filecache_Object (void); + // Only if reference count is zero should this be called. + + int acquire (void); + // Increment the reference_count_. + + int release (void); + // Decrement the reference_count_. + + // = action_ accessors + int action (void) const; + int action (int action_value); + + // = error_ accessors + int error (void) const; + int error (int error_value, + const char *s = "ACE_Filecache_Object"); + + const char *filename (void) const; + // filename_ accessor + + ACE_HANDLE handle (void) const; + // handle_ accessor. + + void *address (void) const; + // Base memory address for memory mapped file. + + size_t size (void) const; + // size_ accessor. + + int update (void) const; + // True if file on disk is newer than cached file. + +protected: + ACE_Filecache_Object (void); + // Prevent from being called. + + void init (void); + // Common initialization code, + +private: + int error_i (int error_value, + const char *s = "ACE_Filecache_Object"); + // Internal error logging method, no locking. + +public: + + enum + { + READING = 1, + WRITING = 2 + }; + + enum + { + SUCCESS = 0, + ACCESS_FAILED, + OPEN_FAILED, + COPY_FAILED, + STAT_FAILED, + MEMMAP_FAILED, + WRITE_FAILED + }; + +private: + char *tempname_; + char filename_[MAXPATHLEN + 1]; + // The temporary file name and the real file name. The real file is + // copied into the temporary file for safety reasons. + + ACE_Mem_Map mmap_; + ACE_HANDLE handle_; + // mmap_ holds the memory mapped version of the temporary file. + // handle_ is the descriptor to the temporary file. + + struct stat stat_; + size_t size_; + // Used to compare against the real file to test if an update is needed. + + int action_; + int error_; + // Status indicators. + + int reference_count_; + ACE_SYNCH_RW_MUTEX lock_; + // reference_count_ counts how many users of the file there are. + // lock_ provides a synchronization mechanism for critical sections + // of code. +}; + void ACE_Filecache_Handle::init (void) { @@ -177,6 +282,51 @@ ACE_Filecache::~ACE_Filecache (void) } ACE_Filecache_Object * +ACE_Filecache::find (const char * filename) +{ + int i; + ACE_Filecache_Object *handle = 0; + + { + ACE_Read_Guard<ACE_SYNCH_RW_MUTEX> m (ACE_Filecache::lock_); + + i = this->fetch_i (filename); + + if (i != -1 && ! this->table_[i]->update ()) + handle = this->table_[i]; + } + + // Considerably slower on misses, but should be faster on hits. + // This is actually the double check locking pattern. + + if (handle == 0) + { + ACE_Write_Guard<ACE_SYNCH_RW_MUTEX> m (ACE_Filecache::lock_); + + i = this->fetch_i (filename); + + if (i == -1) + { + ACE_DEBUG ((LM_DEBUG, " (%t) CVF: missed %s\n", filename)); + } + else if (this->table_[i]->update ()) + { + ACE_DEBUG ((LM_DEBUG, " (%t) CVF: updating %s\n", filename)); + this->remove_i (i); + handle = this->table_[i] = new ACE_Filecache_Object (filename); + handle->acquire (); + } + else + { + ACE_DEBUG ((LM_DEBUG, " (%t) CVF: found %s\n", filename)); + handle = this->table_[i]; + } + } + + return handle; +} + +ACE_Filecache_Object * ACE_Filecache::fetch (const char * filename) { int i; @@ -194,6 +344,9 @@ ACE_Filecache::fetch (const char * filename) // Considerably slower on misses, but should be faster on hits. // This is actually the double check locking pattern. + // Nearly equivalent to this->find (), except a miss causes the CVF + // to insert the file into the cache. + if (handle == 0) { ACE_Write_Guard<ACE_SYNCH_RW_MUTEX> m (ACE_Filecache::lock_); diff --git a/ace/Filecache.h b/ace/Filecache.h index 499a121174b..86a0eb493c5 100644 --- a/ace/Filecache.h +++ b/ace/Filecache.h @@ -134,6 +134,10 @@ public: ~ACE_Filecache (void); + ACE_Filecache_Object *find (const char *filename); + // Return the file associated with ``filename'' if it is in the cache, + // or NULL if not. + ACE_Filecache_Object *fetch (const char *filename); // Return the file associated with ``filename'' if it is in the cache, // or create if not. @@ -181,109 +185,4 @@ private: static ACE_SYNCH_RW_MUTEX lock_; }; -class ACE_Export ACE_Filecache_Object - // = TITLE - // Abstraction over a real file. This is what the Virtual - // Filesystem contains. This class is not intended for general - // consumption. Please consult a physician before attempting to - // use this class. -{ -public: - ACE_Filecache_Object (const char *filename); - // Creates a file for reading. - - ACE_Filecache_Object (const char *filename, - int size); - // Creates a file for writing. - - ~ACE_Filecache_Object (void); - // Only if reference count is zero should this be called. - - int acquire (void); - // Increment the reference_count_. - - int release (void); - // Decrement the reference_count_. - - // = action_ accessors - int action (void) const; - int action (int action_value); - - // = error_ accessors - int error (void) const; - int error (int error_value, - const char *s = "ACE_Filecache_Object"); - - const char *filename (void) const; - // filename_ accessor - - ACE_HANDLE handle (void) const; - // handle_ accessor. - - void *address (void) const; - // Base memory address for memory mapped file. - - size_t size (void) const; - // size_ accessor. - - int update (void) const; - // True if file on disk is newer than cached file. - -protected: - ACE_Filecache_Object (void); - // Prevent from being called. - - void init (void); - // Common initialization code, - -private: - int error_i (int error_value, - const char *s = "ACE_Filecache_Object"); - // Internal error logging method, no locking. - -public: - - enum - { - READING = 1, - WRITING = 2 - }; - - enum - { - SUCCESS = 0, - ACCESS_FAILED, - OPEN_FAILED, - COPY_FAILED, - STAT_FAILED, - MEMMAP_FAILED, - WRITE_FAILED - }; - -private: - char *tempname_; - char filename_[MAXPATHLEN + 1]; - // The temporary file name and the real file name. The real file is - // copied into the temporary file for safety reasons. - - ACE_Mem_Map mmap_; - ACE_HANDLE handle_; - // mmap_ holds the memory mapped version of the temporary file. - // handle_ is the descriptor to the temporary file. - - struct stat stat_; - size_t size_; - // Used to compare against the real file to test if an update is needed. - - int action_; - int error_; - // Status indicators. - - int reference_count_; - ACE_SYNCH_RW_MUTEX lock_; - // reference_count_ counts how many users of the file there are. - // lock_ provides a synchronization mechanism for critical sections - // of code. -}; - #endif /* ACE_FILECACHE_H */ diff --git a/apps/JAWS/ChangeLog b/apps/JAWS/ChangeLog index 2a1872dae2b..d2df4eb20ca 100644 --- a/apps/JAWS/ChangeLog +++ b/apps/JAWS/ChangeLog @@ -1,3 +1,11 @@ +Wed Jul 9 13:08:00 1997 James C Hu <jxh@lambada.cs.wustl.edu> + + * clients/Caching/http_handler.cpp (svc): Added code to check to + see if the file is already cached before trying to cache it. + + * clients/Caching/http_client.cpp (main): Added a comment block at + the top of the file. + Mon Jul 7 23:40:13 1997 Nanbor Wang <nw1@cumbia.cs.wustl.edu> * clients/WebSTONE/src/webclient.c: Removed a bunch of THREAD diff --git a/apps/JAWS/clients/Caching/Makefile b/apps/JAWS/clients/Caching/Makefile new file mode 100644 index 00000000000..cc1b7f30a7b --- /dev/null +++ b/apps/JAWS/clients/Caching/Makefile @@ -0,0 +1,49 @@ +#---------------------------------------------------------------------------- +# %W% %G% +# +# Makefile for the ACE Adapter Web Server (JAWS) client +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +BIN = http_client + +FILES = http_handler + +LSRC = $(addsuffix .cpp,$(FILES)) +LOBJ = $(addsuffix .o,$(FILES)) +SHOBJ = $(addsuffix .so,$(FILES)) + +LDLIBS = $(addprefix .shobj/,$(SHOBJ)) + +VLDLIBS = $(LDLIBS:%=%$(VAR)) + +BUILD = $(VBIN) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU +include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Dependencies +#---------------------------------------------------------------------------- +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + + + +# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/apps/JAWS/clients/Caching/http_client.cpp b/apps/JAWS/clients/Caching/http_client.cpp new file mode 100644 index 00000000000..6390bd230ab --- /dev/null +++ b/apps/JAWS/clients/Caching/http_client.cpp @@ -0,0 +1,66 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// apps/JAWS/clients/Caching +// +// = FILENAME +// http_client.cpp +// +// = AUTHOR +// James Hu +// +// ============================================================================ + +// = DESCRIPTION +// This is a very simple client. It accepts URLs from a prompt, and +// will try to fetch them. Also accepts shell escapes. + +#include "http_handler.h" + +int +main (int argc, char *argv[]) +{ + argc = argc; + argv = argv; + + // Present a command line. + // * Accept a URL. + // Pass it to the HTTP_Connector. + // Connect. + // Report status. + // * Accept shell escape character. + + char buf[BUFSIZ]; + + ACE_OS::fprintf (stderr, "* "); + while (ACE_OS::fgets (buf, sizeof (buf), stdin) != NULL) + { + char * s = buf; + while (*s == ' ' || *s == '\t') + s++; + + if (*s == '!') + { + // Shell command + do s++; while (*s == ' ' || *s == '\t'); + if (ACE_OS::system (s) == -1) + ACE_OS::fprintf (stderr, " ! Error executing: %s\n", s); + } + else if (ACE_OS::strncmp (s, "http://", 7) == 0) + { + // URL + HTTP_Connector connector; + connector.connect (s); + } + else + ACE_OS::fprintf (stderr, " ? I don't understand: %s\n", s); + + ACE_OS::fprintf (stderr, "* "); + } + + ACE_DEBUG ((LM_DEBUG, "\nBye!\n")); + + return 0; +} diff --git a/apps/JAWS/clients/Caching/http_handler.cpp b/apps/JAWS/clients/Caching/http_handler.cpp new file mode 100644 index 00000000000..72bc1760d8d --- /dev/null +++ b/apps/JAWS/clients/Caching/http_handler.cpp @@ -0,0 +1,248 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// apps/JAWS/clients/Caching +// +// = FILENAME +// http_handler.cpp +// +// = AUTHOR +// James Hu +// +// ============================================================================ + +#include "http_handler.h" +#include "ace/Filecache.h" + +HTTP_Handler::HTTP_Handler (void) +{ +} + +HTTP_Handler::HTTP_Handler (const char * path) +{ + // How long is the request going to be? + this->request_[0] = '\0'; + this->request_size_ = + ACE_OS::strlen ("GET ") + + ACE_OS::strlen (path) + + ACE_OS::strlen (" HTTP/1.0\r\nAccept: HTTP/1.0\r\n\r\n"); + + // Make the request. + if ((unsigned int) this->request_size_ < sizeof (this->request_)) + ACE_OS::sprintf(this->request_, + "GET %s HTTP/1.0\r\nAccept: HTTP/1.0\r\n\r\n", + path); + + // Find the filename. + const char * last = ACE_OS::strrchr (path, '/'); + if (last == 0) last = path; + else if (last[1] == '\0') last = "index.html"; + else last = last+1; + + ACE_OS::sprintf(this->filename_, "%s", last); +} + +int +HTTP_Handler::open (void *) +{ + // If you want threads, use the activate stuff. +#if 0 + if (this->activate () != 0) + { + ACE_ERROR_RETURN((LM_ERROR, "HTTP_Handler::open, whups!\n"), -1); + } +#else + return this->svc (); +#endif /* 0 */ + + return 0; +} + +int +HTTP_Handler::svc (void) +{ + static char buf[BUFSIZ]; + int count = 0; + + // First check the cache. + if (ACE_Filecache::instance ()->find (this->filename_)) + { + ACE_OS::fprintf (stdout, " ``%s'' is already cached.\n", + this->filename_); + return 0; + } + + ACE_DEBUG ((LM_DEBUG, "[%t] sending request --\n%s", this->request_)); + + this->send_n (this->request_, this->request_size_); + + // Read in characters until encounter \r\n\r\n + int done = 0; + char * contentlength; + do + { + while (((count += this->recv_n (buf+count, 1)) > 0) + && ((unsigned int) count < sizeof (buf))) + { + buf[count] = '\0'; + if (count < 2) continue; + done = (strcmp (buf+count-4, "\n\n") == 0); + if (done) break; + if (count < 4) continue; + done = (strcmp (buf+count-4, "\r\n\r\n") == 0); + if (done) break; + } + + if (!done) + { + char * last = ACE_OS::strrchr (buf, '\n'); + last[0] = '\0'; + if ((contentlength = ACE_OS::strstr (buf, "\nContent-length:")) + || (contentlength = ACE_OS::strstr (buf, "\nContent-Length:"))) + done = 1; + else + { + last[0] = '\n'; + count = ACE_OS::strlen (last); + ACE_OS::memmove (buf, last, count + 1); + } + } + else + { + if (!(contentlength = ACE_OS::strstr (buf, "\nContent-length:"))) + contentlength = ACE_OS::strstr (buf, "\nContent-Length:"); + } + + } + while (!done); + + // ASSERT (contentlength != 0) + if (contentlength + && (::sscanf (contentlength, "\nContent-%*[lL]ength: %d ", + &(this->response_size_)) == 1)) + { + ACE_Filecache_Handle afh(this->filename_, this->response_size_); + + this->recv_n (afh.address (), this->response_size_); + + ACE_OS::fprintf (stdout, " ``%s'' is now cached.\n", + this->filename_); + } + else + { + // Maybe we should do something more clever here, such as + // extend ACE_Filecache_Handle to allow the creation of cache + // objects whose size is unknown? + + // Another possibility is to write the contents out to a file, + // and then cache it. + + // Perhaps make ACE_Filecache_Handle more savvy, and allow a + // constructor which accepts a PEER as a parameter. + ACE_DEBUG ((LM_DEBUG, "HTTP_Handler, no content-length header!\n")); + } + + return 0; +} + +int +HTTP_Handler::send_n (const void *buf, size_t n) +{ + int count = 0; + const char *p = (const char *) buf; + do + { + int result = this->peer ().send (p+count, n - count); + if (result <= 0) + { + if (result < 0) + ACE_DEBUG ((LM_DEBUG, "HTTP_Handler::send_n, error %p\n")); + break; + } + count += result; + } + while ((unsigned int) count < n); + + return count; +} + +int +HTTP_Handler::recv_n (void *buf, size_t n) +{ + int count = 0; + char *p = (char *) buf; + + do + { + int result = this->peer ().recv (p+count, n - count); + if (result <= 0) + { + if (result < 0) + ACE_DEBUG ((LM_DEBUG, "HTTP_Handler::recv_n, error %p\n")); + break; + } + count += result; + } + while ((unsigned int) count < n); + + return count; +} + +int +HTTP_Connector::connect (const char * url) +{ + char host[BUFSIZ]; + unsigned short port; + char path[BUFSIZ]; + + if (this->parseurl (url, host, &port, path) == -1) + { + ACE_DEBUG ((LM_DEBUG, "HTTP_Connector, error parsing url: %s\n", url)); + return -1; + } + + HTTP_Handler hh (path); + HTTP_Handler *hhptr = &hh; + return this->connector_.connect (hhptr, ACE_INET_Addr (port, host)); +} + +#define DEFAULT_SERVER_PORT 80 + +// extract the main components of a URL +int +HTTP_Connector::parseurl(const char *url, + char *host, unsigned short *port, char *path) +{ + int status = 0; + + // hackish, but useful + if (3 != ::sscanf(url, "http://%[^:/]:%hu%s", host, port, path)) { + if (2 != ::sscanf(url, "http://%[^:/]:%hu", host, port)) { + if (2 != ::sscanf(url, "http://%[^:/]%s", host, path)) { + if (1 != ::sscanf(url, "http://%[^:/]", host)) { + status = -1; + } + else { *port = DEFAULT_SERVER_PORT; ACE_OS::strcpy(path, "/"); } + } + else *port = DEFAULT_SERVER_PORT; + } + else ACE_OS::strcpy(path, "/"); + } + + // 0 => success + // -1 => error + return status; +} + +#if defined (ACE_TEMPLATES_REQUIRE_SPECIALIZATION) +template class ACE_Connector<HTTP_Handler,ACE_SOCK_CONNECTOR>; + +template class ACE_Svc_Tuple<HTTP_Handler>; +template class ACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>; + +template class ACE_Map_Entry<ACE_HANDLE,ACE_Svc_Tuple<HTTP_Handler>*>; +template class ACE_Map_Manager<ACE_HANDLE,ACE_Svc_Tuple<HTTP_Handler>*,ACE_SYNCH_RW_MUTEX>; +template class ACE_Map_Iterator<ACE_HANDLE,ACE_Svc_Tuple<HTTP_Handler>*,ACE_SYNCH_RW_MUTEX>; +#endif /* ACE_TEMPLATES_REQUIRE_SPECIALIZATION */ diff --git a/apps/JAWS/clients/Caching/http_handler.h b/apps/JAWS/clients/Caching/http_handler.h new file mode 100644 index 00000000000..68559323501 --- /dev/null +++ b/apps/JAWS/clients/Caching/http_handler.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ + +#include "ace/Connector.h" +#include "ace/SOCK_Connector.h" + +class HTTP_Handler + : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ +public: + HTTP_Handler (void); + HTTP_Handler (const char * path); + + virtual int open (void *); + virtual int svc (void); + +private: + int send_n (const void *, size_t); + int recv_n (void *, size_t); + +private: + char request_[BUFSIZ]; + int request_size_; + + char filename_[BUFSIZ]; + int response_size_; +}; + +class HTTP_Connector +{ +public: + int connect (const char * url); + +private: + int parseurl (const char *url, char *host, unsigned short *port, char *path); + +private: + ACE_Connector<HTTP_Handler, ACE_SOCK_CONNECTOR> connector_; +}; + |