summaryrefslogtreecommitdiff
path: root/ACE/apps/JAWS/server
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/apps/JAWS/server')
-rw-r--r--ACE/apps/JAWS/server/HTTP_Config.cpp140
-rw-r--r--ACE/apps/JAWS/server/HTTP_Config.h95
-rw-r--r--ACE/apps/JAWS/server/HTTP_Handler.cpp314
-rw-r--r--ACE/apps/JAWS/server/HTTP_Handler.h221
-rw-r--r--ACE/apps/JAWS/server/HTTP_Helpers.cpp442
-rw-r--r--ACE/apps/JAWS/server/HTTP_Helpers.h109
-rw-r--r--ACE/apps/JAWS/server/HTTP_Request.cpp664
-rw-r--r--ACE/apps/JAWS/server/HTTP_Request.h202
-rw-r--r--ACE/apps/JAWS/server/HTTP_Response.cpp388
-rw-r--r--ACE/apps/JAWS/server/HTTP_Response.h80
-rw-r--r--ACE/apps/JAWS/server/HTTP_Server.cpp431
-rw-r--r--ACE/apps/JAWS/server/HTTP_Server.h155
-rw-r--r--ACE/apps/JAWS/server/IO.cpp570
-rw-r--r--ACE/apps/JAWS/server/IO.h296
-rw-r--r--ACE/apps/JAWS/server/JAWS_Concurrency.cpp82
-rw-r--r--ACE/apps/JAWS/server/JAWS_Concurrency.h101
-rw-r--r--ACE/apps/JAWS/server/JAWS_Pipeline.cpp29
-rw-r--r--ACE/apps/JAWS/server/JAWS_Pipeline.h36
-rw-r--r--ACE/apps/JAWS/server/JAWS_Pipeline_Handler.cpp25
-rw-r--r--ACE/apps/JAWS/server/JAWS_Pipeline_Handler.h29
-rw-r--r--ACE/apps/JAWS/server/Makefile.am95
-rw-r--r--ACE/apps/JAWS/server/Parse_Headers.cpp362
-rw-r--r--ACE/apps/JAWS/server/Parse_Headers.h121
-rw-r--r--ACE/apps/JAWS/server/README228
-rw-r--r--ACE/apps/JAWS/server/jaws.auth2
-rw-r--r--ACE/apps/JAWS/server/main.cpp57
-rw-r--r--ACE/apps/JAWS/server/server.mpc36
-rw-r--r--ACE/apps/JAWS/server/svc.conf49
-rwxr-xr-xACE/apps/JAWS/server/test.cgi9
29 files changed, 5368 insertions, 0 deletions
diff --git a/ACE/apps/JAWS/server/HTTP_Config.cpp b/ACE/apps/JAWS/server/HTTP_Config.cpp
new file mode 100644
index 00000000000..11890037d3c
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Config.cpp
@@ -0,0 +1,140 @@
+// $Id$
+
+// HTTP_Config.cpp
+
+#include "ace/OS_NS_stdlib.h"
+#include "HTTP_Config.h"
+
+ACE_RCSID(server, HTTP_Config, "$Id$")
+
+// static HTTP_Config_Info config_info;
+
+HTTP_Config_Info *HTTP_Config::instance_ = 0;
+
+HTTP_Config_Info *
+HTTP_Config::instance (void)
+{
+ if (HTTP_Config::instance_ == 0)
+ {
+ HTTP_Config::instance_ = new HTTP_Config_Info;
+
+ HTTP_Config::instance_->document_root (0);
+ HTTP_Config::instance_->cgi_path (0);
+ HTTP_Config::instance_->user_dir (0);
+ HTTP_Config::instance_->dir_index (0);
+ HTTP_Config::instance_->proxy_flag (0);
+ }
+
+ return HTTP_Config::instance_;
+}
+
+HTTP_Config_Info::HTTP_Config_Info (void)
+ : document_root_ (0),
+ cgi_path_ (0),
+ user_dir_ (0),
+ dir_index_ (0),
+ proxy_flag_ (0)
+{
+}
+
+HTTP_Config_Info::~HTTP_Config_Info (void)
+{
+}
+
+const char *
+HTTP_Config_Info::document_root (void) const
+{
+ return this->document_root_;
+}
+
+const char *
+HTTP_Config_Info::cgi_path (void) const
+{
+ return this->cgi_path_;
+}
+
+const char *
+HTTP_Config_Info::user_dir (void) const
+{
+ return this->user_dir_;
+}
+
+const char *
+HTTP_Config_Info::dir_index (void) const
+{
+ return this->dir_index_;
+}
+
+int
+HTTP_Config_Info::proxy_flag (void) const
+{
+ return this->proxy_flag_;
+}
+
+const char *
+HTTP_Config_Info::document_root (const char *dr_string)
+{
+ if (dr_string)
+ this->document_root_ = dr_string;
+ else
+ {
+ this->document_root_ = ACE_OS::getenv ("JAWS_DOCUMENT_ROOT");
+ if (!this->document_root_)
+ this->document_root_ = ".";
+ }
+
+ return this->document_root_;
+}
+
+const char *
+HTTP_Config_Info::cgi_path (const char *cp_string)
+{
+ if (cp_string)
+ this->cgi_path_ = cp_string;
+ else
+ {
+ this->cgi_path_ = ACE_OS::getenv ("JAWS_CGI_PATH");
+
+ if (!this->cgi_path_)
+ this->cgi_path_ = "cgi-bin";
+ }
+
+ return this->cgi_path_;
+}
+
+const char *
+HTTP_Config_Info::user_dir (const char *ud_string)
+{
+ if (ud_string)
+ this->user_dir_ = ud_string;
+ else
+ {
+ this->user_dir_ = ACE_OS::getenv ("JAWS_USER_DIR");
+ if (!this->user_dir_)
+ this->user_dir_ = ".www";
+ }
+
+ return this->user_dir_;
+}
+
+const char *
+HTTP_Config_Info::dir_index (const char *di_string)
+{
+ if (di_string)
+ this->dir_index_ = di_string;
+ else
+ {
+ this->dir_index_ = ACE_OS::getenv ("JAWS_DIR_INDEX");
+ if (!this->dir_index_)
+ this->dir_index_ = "index.html";
+ }
+
+ return this->dir_index_;
+}
+
+int
+HTTP_Config_Info::proxy_flag (int pf)
+{
+ this->proxy_flag_ = pf;
+ return this->proxy_flag_;
+}
diff --git a/ACE/apps/JAWS/server/HTTP_Config.h b/ACE/apps/JAWS/server/HTTP_Config.h
new file mode 100644
index 00000000000..39c76c44d1b
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Config.h
@@ -0,0 +1,95 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// HTTP_Config.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+// = Forward declaration.
+class HTTP_Config_Info;
+
+class HTTP_Config
+ // = TITLE
+ // Stores server configuration information.
+ // Someday, this will be hip and cool and be able to parse
+ // NCSA httpd style config files like Apache does. For now,
+ // I'm just going to hack in environment variable stuff.
+ //
+ // Designed around Singleton pattern.
+{
+public:
+ static HTTP_Config_Info *instance (void);
+ // Access the Singleton.
+
+private:
+ static HTTP_Config_Info *instance_;
+ // Store the Singleton.
+};
+
+class HTTP_Config_Info
+ // = TITLE
+ // This is where the information is really stored.
+{
+friend class HTTP_Config;
+public:
+ HTTP_Config_Info (void);
+ ~HTTP_Config_Info (void);
+
+ // Accessors to the information
+
+ const char *document_root (void) const;
+ // Where the root of the document tree begins. This prevents
+ // clients from being able to examine your entire filesystem.
+
+ const char *cgi_path (void) const;
+ // A search path for CGI files.
+
+ const char *user_dir (void) const;
+ // The directory which is appended to a home user directory, e.g.,
+ // ".www-docs" or "public_html".
+
+ const char *dir_index (void) const;
+ // What is the default index file for a directory, e.g.,
+ // "index.html".
+
+ int proxy_flag (void) const;
+ // Will the server support proxy requests?
+
+private:
+ // = Accesors that can set the data
+
+ const char *document_root (const char *dr_string);
+ const char *cgi_path (const char *cp_string);
+ const char *user_dir (const char *ud_string);
+ const char *dir_index (const char *di_string);
+
+ int proxy_flag (int pf);
+
+private:
+ // = Data members
+
+ const char *document_root_;
+ // The directory root from which documents will be fetched
+
+ const char *cgi_path_;
+ // The directories from which to expect CGI scripts
+
+ const char *user_dir_;
+ // Name of the sub-directory where user Web pages are
+
+ const char *dir_index_;
+ // Name of the Web page to present in place of a directory listing
+
+ int proxy_flag_;
+ // Should we support proxy requests? Ignored for now.
+};
diff --git a/ACE/apps/JAWS/server/HTTP_Handler.cpp b/ACE/apps/JAWS/server/HTTP_Handler.cpp
new file mode 100644
index 00000000000..277cfb11f3a
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Handler.cpp
@@ -0,0 +1,314 @@
+// $Id$
+
+// HTTP_Service.cpp -- simple implementation of the HTTP protocol
+
+#include "ace/Message_Block.h"
+#include "ace/Filecache.h"
+
+#include "HTTP_Handler.h"
+#include "HTTP_Helpers.h"
+#include "IO.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/OS_NS_stdio.h"
+
+ACE_RCSID(server, HTTP_Handler, "$Id$")
+
+HTTP_Handler::HTTP_Handler (JAWS_IO &io,
+ HTTP_Handler_Factory &factory)
+ : factory_ (factory),
+ request_data_ (0),
+ handle_ (ACE_INVALID_HANDLE),
+ response_ (io, request_),
+ io_ (io)
+{
+ this->io_.handler (this);
+}
+
+HTTP_Handler::~HTTP_Handler (void)
+{
+ this->request_data_->release ();
+ this->request_data_ = 0;
+}
+
+void
+HTTP_Handler::open (ACE_HANDLE handle,
+ ACE_Message_Block &initial_data)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) New connection \n"));
+
+ int sockbufsize = HTTP_Handler::MAX_SOCKBUFSIZE;
+ int result = ACE_OS::setsockopt (handle,
+ SOL_SOCKET,
+ SO_RCVBUF,
+ (char *) &sockbufsize,
+ sizeof sockbufsize);
+
+ if (result == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "SO_RCVBUF"));
+
+ sockbufsize = HTTP_Handler::MAX_SOCKBUFSIZE;
+
+ result = ACE_OS::setsockopt (handle,
+ SOL_SOCKET,
+ SO_SNDBUF,
+ (char *) &sockbufsize,
+ sizeof sockbufsize);
+ if (result == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "SO_SNDBUF"));
+
+ this->handle_ = handle;
+ this->io_.handle (this->handle_);
+
+ this->request_data_ = initial_data.duplicate ();
+ this->read_complete (initial_data);
+}
+
+void
+HTTP_Handler::read_complete (ACE_Message_Block &message_block)
+{
+ // This is actually a callback entry point. The JAWS_IO framework
+ // calls into this method after some data has been read in.
+
+ switch (this->request_.parse_request (message_block))
+ {
+ case 0:
+ do
+ {
+ int next_read_size
+ = HTTP_Handler::MAX_REQUEST_SIZE - message_block.length ();
+
+ if (next_read_size == 0)
+ {
+ this->request_too_long ();
+ return;
+ }
+
+ this->io_.read (message_block, next_read_size);
+ }
+ while (0);
+ break;
+
+ default:
+ // this->request_.respond ();
+ this->response_.process_request ();
+ }
+}
+
+void
+HTTP_Handler::receive_file_complete (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s received successfully\n",
+ request_.uri ()));
+
+ char buffer[BUFSIZ];
+ int buflen =
+ ACE_OS::sprintf (buffer,
+ "%s %d %s\r\n",
+ this->request_.version (),
+ HTTP_Status_Code::STATUS_OK,
+ "Successful");
+
+ this->io_.send_confirmation_message (buffer, buflen);
+}
+
+void
+HTTP_Handler::receive_file_error (int result)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s error in receiving file\n",
+ request_.uri ()));
+
+ char buffer[BUFSIZ];
+
+ int status_code;
+ switch (result)
+ {
+ case ACE_Filecache_Handle::ACE_ACCESS_FAILED:
+ case ACE_Filecache_Handle::ACE_WRITE_FAILED:
+ case ACE_Filecache_Handle::ACE_OPEN_FAILED:
+ status_code = HTTP_Status_Code::STATUS_NOT_FOUND;
+ break;
+ case ACE_Filecache_Handle::ACE_COPY_FAILED:
+ case ACE_Filecache_Handle::ACE_STAT_FAILED:
+ case ACE_Filecache_Handle::ACE_MEMMAP_FAILED:
+ status_code = HTTP_Status_Code::STATUS_FORBIDDEN;
+ break;
+ default:
+ status_code = HTTP_Status_Code::STATUS_INTERNAL_SERVER_ERROR;
+ break;
+ }
+ int buflen =
+ ACE_OS::sprintf (buffer,
+ "%s %d %s",
+ this->request_.version (),
+ status_code,
+ "Failed");
+
+ this->io_.send_confirmation_message (buffer, buflen);
+}
+
+void
+HTTP_Handler::confirmation_message_complete (void)
+{
+ this->done ();
+}
+
+void
+HTTP_Handler::error_message_complete (void)
+{
+ this->done ();
+}
+
+void
+HTTP_Handler::transmit_file_complete (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s transmitted successfully\n",
+ request_.uri ()));
+
+ this->done ();
+}
+
+void
+HTTP_Handler::transmit_file_error (int result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ " (%t) %s error in transmitting file\n",
+ request_.uri ()));
+
+ int status_code;
+
+ switch (result)
+ {
+ case ACE_Filecache_Handle::ACE_ACCESS_FAILED:
+ case ACE_Filecache_Handle::ACE_WRITE_FAILED:
+ case ACE_Filecache_Handle::ACE_OPEN_FAILED:
+ status_code = HTTP_Status_Code::STATUS_NOT_FOUND;
+ break;
+ case ACE_Filecache_Handle::ACE_COPY_FAILED:
+ case ACE_Filecache_Handle::ACE_STAT_FAILED:
+ case ACE_Filecache_Handle::ACE_MEMMAP_FAILED:
+ status_code = HTTP_Status_Code::STATUS_FORBIDDEN;
+ break;
+ default:
+ status_code = HTTP_Status_Code::STATUS_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ this->response_.error_response (status_code, "error in transmitting file");
+}
+
+void
+HTTP_Handler::read_error (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) error in reading request\n"));
+ this->done ();
+}
+
+void
+HTTP_Handler::write_error (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s error in writing response\n",
+ request_.uri ()));
+
+ this->done ();
+}
+
+void
+HTTP_Handler::timeout (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s error in reading request\n",
+ request_.uri ()));
+
+ this->response_.
+ error_response (HTTP_Status_Code::STATUS_INTERNAL_SERVER_ERROR,
+ "error in reading request");
+}
+
+void
+HTTP_Handler::request_too_long (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) request too long\n"));
+ this->response_.
+ error_response (HTTP_Status_Code::STATUS_BAD_REQUEST,
+ "request too long");
+}
+
+void
+HTTP_Handler::done (void)
+{
+ this->factory_.destroy_http_handler (*this, this->io_);
+}
+
+HTTP_Handler_Factory::~HTTP_Handler_Factory (void)
+{
+}
+
+HTTP_Handler *
+Synch_HTTP_Handler_Factory::create_http_handler (void)
+{
+ JAWS_Synch_IO *io;
+ ACE_NEW_RETURN (io, JAWS_Synch_IO, 0);
+ HTTP_Handler *handler;
+ ACE_NEW_RETURN (handler, HTTP_Handler (*io, *this), 0);
+
+ return handler;
+}
+
+void
+Synch_HTTP_Handler_Factory::destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io)
+{
+ delete &io;
+ delete &handler;
+}
+
+//-------------SYNCH IO no Cache
+
+HTTP_Handler *
+No_Cache_Synch_HTTP_Handler_Factory::create_http_handler (void)
+{
+ JAWS_Synch_IO_No_Cache *io;
+ ACE_NEW_RETURN (io, JAWS_Synch_IO_No_Cache, 0);
+ HTTP_Handler *handler;
+ ACE_NEW_RETURN (handler, HTTP_Handler (*io, *this), 0);
+
+ return handler;
+}
+
+void
+No_Cache_Synch_HTTP_Handler_Factory::destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io)
+{
+ delete &io;
+ delete &handler;
+}
+
+//----------------
+
+// This only works on Win32
+#if defined (ACE_WIN32)
+void
+Asynch_HTTP_Handler_Factory::open (ACE_HANDLE handle,
+ ACE_Message_Block &mb)
+{
+ JAWS_Asynch_IO *io;
+ ACE_NEW (io, JAWS_Asynch_IO);
+ HTTP_Handler *handler;
+ ACE_NEW (handler, HTTP_Handler (*io, *this));
+ handler->open (handle, mb);
+}
+
+void
+Asynch_HTTP_Handler_Factory::destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io)
+{
+ delete &handler;
+ delete &io;
+ delete this;
+}
+
+HTTP_Handler *
+Asynch_HTTP_Handler_Factory::create_http_handler (void)
+{
+ return 0;
+}
+#endif /* ACE_WIN32 */
diff --git a/ACE/apps/JAWS/server/HTTP_Handler.h b/ACE/apps/JAWS/server/HTTP_Handler.h
new file mode 100644
index 00000000000..f7eb9b9a693
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Handler.h
@@ -0,0 +1,221 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// HTTP_Handler.h
+//
+// = AUTHOR
+// James Hu and Irfan Pyarali
+//
+// ============================================================================
+
+#ifndef HTTP_HANDLER_H
+#define HTTP_HANDLER_H
+
+// = Forward declarations
+class Message_Block;
+class HTTP_Handler_Factory;
+
+#include "ace/Asynch_IO.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "HTTP_Request.h"
+#include "HTTP_Response.h"
+#include "IO.h"
+
+class HTTP_Handler : protected JAWS_IO_Handler
+ // = TITLE
+ //
+ // This class is used to implement the HTTP protocol
+ //
+ // = DESCRIPTION
+ //
+ // The HTTP_Handler class is a state based implementation of the
+ // HTTP protocol. Therefore, it can be used synchronously and
+ // asynchronously. It uses an abstract IO class to move between
+ // different HTTP protocol states. It is up to the IO class to
+ // decide on synchronous or asynchronous I/O.
+{
+ // Friend I/O classes. Can call protected methods.
+ friend class JAWS_Synch_IO;
+ friend class JAWS_Synch_IO_No_Cache;
+ friend class JAWS_Asynch_IO;
+
+ // Factories
+ friend class Asynch_HTTP_Handler_Factory;
+ friend class Synch_HTTP_Handler_Factory;
+ friend class No_Cache_Synch_HTTP_Handler_Factory;
+
+public:
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &initial_data);
+ // The handler is initialized with a connection <handle> of a new
+ // client and any <initial_data> that came across. The
+ // <initial_data> block will be of MAX_REQUEST_SIZE and the number
+ // of bytes in <initial_data> can be found from
+ // <initial_data>.length ()
+
+protected:
+ HTTP_Handler (JAWS_IO &io,
+ HTTP_Handler_Factory &factory);
+ // The constructor is passed the factory that created <this> and the
+ // IO mechanism that the handler should use.
+
+ virtual ~HTTP_Handler (void);
+ // Destructor
+
+ virtual void timeout (void);
+ // This method is called by the framework when there is a timeout.
+
+ virtual void done (void);
+ // This is the termination state of the handler. After successful or
+ // unsuccessful completions, the handler will end up in this state
+ // (method).
+
+ virtual void request_too_long (void);
+ // Request too long.
+
+ HTTP_Handler_Factory &factory_;
+ // Reference to the creating factory.
+
+protected:
+ // = Completion methods inherited from <JAWS_IO_Handler>.
+
+ virtual void read_complete (ACE_Message_Block &data);
+ virtual void read_error (void);
+ virtual void transmit_file_complete (void);
+ virtual void transmit_file_error (int result);
+ virtual void receive_file_complete (void);
+ virtual void receive_file_error (int result);
+ virtual void write_error (void);
+ virtual void confirmation_message_complete (void);
+ virtual void error_message_complete (void);
+
+public:
+ enum
+ {
+ MAX_SOCKBUFSIZE = 64 * 1024,
+ MAX_REQUEST_SIZE = 8192,
+ METHODSIZ = 10,
+ VERSIONSIZ = 10
+ };
+
+private:
+ ACE_Message_Block *request_data_;
+ // This points to the request sent by the client
+
+ ACE_HANDLE handle_;
+ // I/O handle to the client
+
+ HTTP_Request request_;
+ HTTP_Response response_;
+
+ JAWS_IO &io_;
+ // IO class used by the handler
+};
+
+class HTTP_Handler_Factory
+ // = TITLE
+ //
+ // This class is used to create new HTTP handlers
+ //
+ // = DESCRIPTION
+ //
+ // This is an abstract factory for creating new HTTP handlers.
+{
+public:
+ virtual ~HTTP_Handler_Factory (void);
+ // Destructor
+
+ virtual HTTP_Handler *create_http_handler (void) = 0;
+ // This creates a new HTTP_Handler
+
+ virtual void destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io) = 0;
+ // The HTTP handler will call this method from HTTP_Handler::done to
+ // tell the factory to reap up the handler as it is now done with
+ // the protocol
+};
+
+class Synch_HTTP_Handler_Factory : public HTTP_Handler_Factory
+ // = TITLE
+ //
+ // This class is used to create new HTTP handlers that will use
+ // Synch IO
+ //
+ // = DESCRIPTION
+{
+public:
+ HTTP_Handler *create_http_handler (void);
+ // This creates a new HTTP_Handler
+
+ void destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io);
+ // The HTTP handler will call this method from HTTP_Handler::done to
+ // tell the factory to reap up the handler as it is now done with
+ // the protocol
+};
+
+//--------------Added a factory for SYNCH IO without caching
+
+class No_Cache_Synch_HTTP_Handler_Factory : public HTTP_Handler_Factory
+ // = TITLE
+ //
+ // This class is used to create new HTTP handlers that will use
+ // Synch IO without caching
+ //
+ // = DESCRIPTION
+{
+public:
+ HTTP_Handler *create_http_handler (void);
+ // This creates a new HTTP_Handler
+
+ void destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io);
+ // The HTTP handler will call this method from HTTP_Handler::done to
+ // tell the factory to reap up the handler as it is now done with
+ // the protocol
+};
+
+//--------------
+
+#if defined (ACE_WIN32)
+class Asynch_HTTP_Handler_Factory : public HTTP_Handler_Factory, public ACE_Service_Handler
+ // = TITLE
+ // This class is used to create new HTTP handlers that will use
+ // Asynchronous IO. This only works on Win32.
+ //
+ // = DESCRIPTION
+{
+public:
+ void destroy_http_handler (HTTP_Handler &handler,
+ JAWS_IO &io);
+ // The HTTP handler will call this method from HTTP_Handler::done to
+ // tell the factory to reap up the handler as it is now done with
+ // the protocol
+
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ // <open> is called by <ACE_Asynch_Acceptor> to initialize a new
+ // instance of ACE_Service_Handler that has been created after the a
+ // new connection is accepted.
+ //
+ // This will act as a creation point for new handlers.
+
+private:
+ HTTP_Handler *create_http_handler (void);
+ // This method is private as users are not allowed to create new
+ // handlers. New handlers can only be created by the framework when
+ // new client connections arrive.
+};
+#endif /* ACE_WIN32 */
+#endif /* HTTP_HANDLER_H */
diff --git a/ACE/apps/JAWS/server/HTTP_Helpers.cpp b/ACE/apps/JAWS/server/HTTP_Helpers.cpp
new file mode 100644
index 00000000000..1ca6bfe198d
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Helpers.cpp
@@ -0,0 +1,442 @@
+// $Id$
+
+// HTTP_Helpers.cpp -- Helper utilities for both server and client
+
+#include "HTTP_Helpers.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Guard_T.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_stdio.h"
+
+ACE_RCSID(server, HTTP_Helpers, "$Id$")
+
+// = Static initialization.
+const char *const
+HTTP_Helper::months_[12]=
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+char const *HTTP_Helper::alphabet_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char * HTTP_Helper::date_string_ = 0;
+ACE_SYNCH_MUTEX HTTP_Helper::mutex_;
+
+ACE_SYNCH_MUTEX HTTP_Status_Code::lock_;
+int HTTP_Status_Code::instance_ = 0;
+const char *HTTP_Status_Code::Reason[HTTP_Status_Code::MAX_STATUS_CODE + 1];
+
+time_t
+HTTP_Helper::HTTP_mktime (const char *httpdate)
+{
+ char *buf;
+
+ ACE_NEW_RETURN (buf, char[ACE_OS::strlen (httpdate) + 1], (time_t) -1);
+
+ // Make spaces in the date be semi-colons so we can parse robustly
+ // with sscanf.
+
+ const char *ptr1 = httpdate;
+ char *ptr2 = buf;
+
+ do
+ {
+ if (*ptr1 == ' ')
+ *ptr2++ = ';';
+ else
+ *ptr2++ = *ptr1;
+ }
+ while (*ptr1++ != '\0');
+
+ // In HTTP/1.0, there are three versions of an HTTP_date.
+
+ // rfc1123-date = wkday "," SP dd month yyyy SP hh:mm:ss SP "GMT"
+ // rfc850-date = weekday "," SP dd-month-yy SP hh:mm:ss SP "GMT"
+ // asctime-date = wkday SP month dd SP hh:mm:ss SP yyyy
+
+ static const char rfc1123_date[] = "%3s,;%2d;%3s;%4d;%2d:%2d:%2d;GMT";
+ static const char rfc850_date[] = "%s,;%2d-%3s-%2d;%2d:%2d:%2d;GMT";
+ static const char asctime_date[] = "%3s;%3s;%2d;%2d:%2d:%2d;%4d";
+
+ // Should also support other versions (such as from NNTP and SMTP)
+ // for robustness, but it should be clear how to extend this.
+
+ struct tm tms;
+ char month[4];
+ char weekday[10];
+
+ if (::sscanf(buf, rfc1123_date,
+ weekday,
+ &tms.tm_mday,
+ month,
+ &tms.tm_year,
+ &tms.tm_hour,
+ &tms.tm_min,
+ &tms.tm_sec) == 7)
+ ;
+ else if (::sscanf(buf, rfc850_date,
+ weekday,
+ &tms.tm_mday, month, &tms.tm_year,
+ &tms.tm_hour, &tms.tm_min, &tms.tm_sec) == 7)
+ {
+ weekday[3] = '\0';
+ }
+ else if (::sscanf(buf, asctime_date,
+ weekday,
+ month, &tms.tm_mday,
+ &tms.tm_hour, &tms.tm_min, &tms.tm_sec,
+ &tms.tm_year) == 7)
+ {
+ }
+
+ delete [] buf;
+
+ tms.tm_year = HTTP_Helper::fixyear (tms.tm_year);
+ tms.tm_mon = HTTP_Helper::HTTP_month (month);
+
+ if (tms.tm_mon == -1)
+ return (time_t) -1;
+
+ // mktime is a Standard C function.
+ {
+
+#if !defined (ACE_HAS_REENTRANT_LIBC)
+ ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> g (HTTP_Helper::mutex_));
+#endif /* NOT ACE_HAS_REENTRANT_LIBC */
+
+ return ACE_OS::mktime (&tms);
+ }
+}
+
+const char *
+HTTP_Helper::HTTP_date (void)
+{
+ if (HTTP_Helper::date_string_ == 0)
+ {
+ ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> m (HTTP_Helper::mutex_));
+
+ if (HTTP_Helper::date_string_ == 0)
+ {
+ // 40 bytes is all I need.
+ ACE_NEW_RETURN (HTTP_Helper::date_string_, char[40], 0);
+
+ if (!HTTP_Helper::HTTP_date (HTTP_Helper::date_string_))
+ {
+ delete [] HTTP_Helper::date_string_;
+ HTTP_Helper::date_string_ = 0;
+ }
+ }
+ }
+
+ return HTTP_Helper::date_string_;
+}
+
+const char *
+HTTP_Helper::HTTP_date (char *s)
+{
+ // Return the date-string formatted per HTTP standards. Time must
+ // be in UTC, so using the 'strftime' call (which obeys the locale)
+ // isn't correct.
+ static const char* months[] = {"Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"};
+ static const char* days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
+
+ time_t tloc;
+ struct tm tms;
+ char * date_string = s;
+
+ if (ACE_OS::time (&tloc) != (time_t) -1
+ && ACE_OS::gmtime_r (&tloc, &tms) != NULL)
+ {
+ ACE_OS::sprintf (date_string,
+ "%s, %2.2d %s %4.4d %2.2d:%2.2d:%2.2d GMT",
+ days[tms.tm_wday], tms.tm_mday, months[tms.tm_mon],
+ tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec);
+ }
+ else
+ date_string = 0;
+
+ return date_string;
+}
+
+int
+HTTP_Helper::HTTP_month (const char *month)
+{
+ for (size_t i = 0; i < 12; i++)
+ if (ACE_OS::strcmp(month, HTTP_Helper::months_[i]) == 0)
+ return i;
+
+ return -1;
+}
+
+const char *
+HTTP_Helper::HTTP_month (int month)
+{
+ if (month < 0 || month >= 12)
+ return 0;
+
+ return HTTP_Helper::months_[month];
+}
+
+// Fix the path if it needs fixing/is fixable.
+
+char *
+HTTP_Helper::HTTP_decode_string (char *path)
+{
+ // replace the percentcodes with the actual character
+ int i, j;
+ char percentcode[3];
+
+ for (i = j = 0; path[i] != '\0'; i++, j++)
+ {
+ if (path[i] == '%')
+ {
+ percentcode[0] = path[++i];
+ percentcode[1] = path[++i];
+ percentcode[2] = '\0';
+ path[j] = (char) ACE_OS::strtol (percentcode, (char **) 0, 16);
+ }
+ else
+ path[j] = path[i];
+ }
+
+ path[j] = path[i];
+
+ return path;
+}
+
+char *
+HTTP_Helper::HTTP_decode_base64 (char *data)
+{
+ char inalphabet[256], decoder[256];
+
+ ACE_OS::memset (inalphabet, 0, sizeof (inalphabet));
+ ACE_OS::memset (decoder, 0, sizeof (decoder));
+
+ for (int i = ACE_OS::strlen (HTTP_Helper::alphabet_) - 1;
+ i >= 0;
+ i--)
+ {
+ inalphabet[(unsigned int) HTTP_Helper::alphabet_[i]] = 1;
+ decoder[(unsigned int) HTTP_Helper::alphabet_[i]] = i;
+ }
+
+ char *indata = data;
+ char *outdata = data;
+
+ int bits = 0;
+ int c;
+ int char_count = 0;
+ int errors = 0;
+
+ while ((c = *indata++) != '\0')
+ {
+ if (c == '=')
+ break;
+ if (c > 255 || ! inalphabet[c])
+ continue;
+ bits += decoder[c];
+ char_count++;
+ if (char_count == 4)
+ {
+ *outdata++ = (bits >> 16);
+ *outdata++ = ((bits >> 8) & 0xff);
+ *outdata++ = (bits & 0xff);
+ bits = 0;
+ char_count = 0;
+ }
+ else
+ bits <<= 6;
+ }
+
+ if (c == '\0')
+ {
+ if (char_count)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "base64 encoding incomplete: at least %d bits truncated\n",
+ ((4 - char_count) * 6)));
+ errors++;
+ }
+ }
+ else
+ {
+ // c == '='
+ switch (char_count)
+ {
+ case 1:
+ ACE_DEBUG ((LM_DEBUG,
+ "base64 encoding incomplete: at least 2 bits missing\n"));
+ errors++;
+ break;
+ case 2:
+ *outdata++ = (bits >> 10);
+ break;
+ case 3:
+ *outdata++ = (bits >> 16);
+ *outdata++ = ((bits >> 8) & 0xff);
+ break;
+ }
+ }
+ *outdata = '\0';
+ return errors ? 0 : data;
+}
+
+char *
+HTTP_Helper::HTTP_encode_base64 (char *data)
+{
+ char buf[BUFSIZ];
+ int c;
+ int error;
+ int char_count = 0;
+ int bits = 0;
+ error = 0;
+ char *indata = data;
+ char *outdata = buf;
+ const unsigned char ASCII_MAX = ~0;
+
+ while ((c = *indata++) != '\0')
+ {
+ if (c > (int)ASCII_MAX)
+ {
+ ACE_DEBUG ((LM_DEBUG, "encountered char > 255 (decimal %d)\n", c));
+ error++;
+ break;
+ }
+ bits += c;
+ char_count++;
+
+ if (char_count == 3)
+ {
+ *outdata++ = HTTP_Helper::alphabet_[bits >> 18];
+ *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f];
+ *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f];
+ *outdata++ = HTTP_Helper::alphabet_[bits & 0x3f];
+ bits = 0;
+ char_count = 0;
+ }
+ else
+ bits <<= 8;
+ }
+
+ if (!error)
+ {
+ if (char_count != 0)
+ {
+ bits <<= 16 - (8 * char_count);
+ *outdata++ = HTTP_Helper::alphabet_[bits >> 18];
+ *outdata++ = HTTP_Helper::alphabet_[(bits >> 12) & 0x3f];
+
+ if (char_count == 1)
+ {
+ *outdata++ = '=';
+ *outdata++ = '=';
+ }
+ else
+ {
+ *outdata++ = HTTP_Helper::alphabet_[(bits >> 6) & 0x3f];
+ *outdata++ = '=';
+ }
+ }
+ *outdata = '\0';
+ ACE_OS::strcpy (data, buf);
+ }
+
+ return (error ? 0 : data);
+}
+
+int
+HTTP_Helper::fixyear (int year)
+{
+ // Fix the year 2000 problem
+
+ if (year > 1000)
+ year -= 1900;
+ else if (year < 100)
+ {
+ struct tm tms;
+ time_t tloc;
+
+ if (ACE_OS::time (&tloc) != (time_t) -1)
+ {
+ ACE_OS::gmtime_r (&tloc, &tms);
+
+ if (tms.tm_year % 100 == year)
+ year = tms.tm_year;
+
+ // The last two cases check boundary conditions, in case the
+ // year just changed at the moment we checked to see if we
+ // need to fix it.
+ if ((year+1) % 100 == tms.tm_year % 100)
+ year = tms.tm_year - 1;
+
+ if (year == (tms.tm_year + 1) % 100)
+ year = tms.tm_year + 1;
+
+ // What to do if none of the above?
+ }
+ }
+
+ return year;
+}
+
+const char **
+HTTP_Status_Code::instance (void)
+{
+ if (HTTP_Status_Code::instance_ == 0)
+ {
+ ACE_MT (ACE_Guard<ACE_SYNCH_MUTEX> g (lock_));
+
+ if (HTTP_Status_Code::instance_ == 0)
+ {
+ for (size_t i = 0;
+ i < HTTP_Status_Code::MAX_STATUS_CODE + 1;
+ i++)
+ {
+ switch (i)
+ {
+ case STATUS_OK:
+ HTTP_Status_Code::Reason[i] = "OK"; break;
+ case STATUS_CREATED:
+ HTTP_Status_Code::Reason[i] = "Created"; break;
+ case STATUS_ACCEPTED:
+ HTTP_Status_Code::Reason[i] = "Accepted"; break;
+ case STATUS_NO_CONTENT:
+ HTTP_Status_Code::Reason[i] = "No Content"; break;
+ case STATUS_MOVED_PERMANENTLY:
+ HTTP_Status_Code::Reason[i] = "Moved Permanently"; break;
+ case STATUS_MOVED_TEMPORARILY:
+ HTTP_Status_Code::Reason[i] = "Moved Temporarily"; break;
+ case STATUS_NOT_MODIFIED:
+ HTTP_Status_Code::Reason[i] = "Not Modified"; break;
+ case STATUS_BAD_REQUEST:
+ HTTP_Status_Code::Reason[i] = "Bad Request"; break;
+ case STATUS_UNAUTHORIZED:
+ HTTP_Status_Code::Reason[i] = "Unauthorized"; break;
+ case STATUS_FORBIDDEN:
+ HTTP_Status_Code::Reason[i] = "Forbidden"; break;
+ case STATUS_NOT_FOUND:
+ HTTP_Status_Code::Reason[i] = "Not Found"; break;
+ case STATUS_INTERNAL_SERVER_ERROR:
+ HTTP_Status_Code::Reason[i] = "Internal Server Error"; break;
+ case STATUS_NOT_IMPLEMENTED:
+ HTTP_Status_Code::Reason[i] = "Not Implemented"; break;
+ case STATUS_BAD_GATEWAY:
+ HTTP_Status_Code::Reason[i] = "Bad Gateway"; break;
+ case STATUS_SERVICE_UNAVAILABLE:
+ HTTP_Status_Code::Reason[i] = "Service Unavailable"; break;
+ default:
+ HTTP_Status_Code::Reason[i] = "Unknown";
+ }
+ }
+
+ HTTP_Status_Code::instance_ = 1;
+ }
+
+ // GUARD released
+ }
+
+ return HTTP_Status_Code::Reason;
+}
diff --git a/ACE/apps/JAWS/server/HTTP_Helpers.h b/ACE/apps/JAWS/server/HTTP_Helpers.h
new file mode 100644
index 00000000000..e7d6eae4f42
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Helpers.h
@@ -0,0 +1,109 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// apps
+//
+// = FILENAME
+// HTTP_Helpers.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef HTTP_HELPERS_H
+#define HTTP_HELPERS_H
+
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class HTTP_Helper
+// Static functions to enhance the lives of HTTP programmers everywhere.
+{
+public:
+
+ // Convert and HTTP-date into a time_t
+ static time_t HTTP_mktime (const char *httpdate);
+
+ // Create today's date
+ static const char *HTTP_date (void);
+ static const char *HTTP_date (char *s);
+
+ // Month conversions (ascii <--> numeric)
+ static int HTTP_month (const char *month);
+ static const char *HTTP_month (int month);
+
+ static char *HTTP_decode_string (char *path);
+
+ // Encode/Decode base64 stuff (weak security model)
+ static char *HTTP_decode_base64 (char *data);
+ static char *HTTP_encode_base64 (char *data);
+
+private:
+
+ static int fixyear (int year);
+
+private:
+ static const char *const months_[12];
+ static char const *alphabet_;
+
+ static char *date_string_;
+ static ACE_SYNCH_MUTEX mutex_;
+ // Use this sometimes (e.g. HTTP_date)
+};
+
+// Design around the Singleton pattern
+
+class HTTP_Status_Code
+ // = TITLE
+ // Go from numeric status codes to descriptive strings.
+ //
+ // = DESCRIPTION
+ // Design around the Singleton pattern
+{
+public:
+ static const char **instance (void);
+ // Singleton access point.
+
+ enum STATUS_CODE
+ {
+ STATUS_OK = 200,
+ STATUS_CREATED = 201,
+ STATUS_ACCEPTED = 202,
+ STATUS_NO_CONTENT = 204,
+ STATUS_MOVED_PERMANENTLY = 301,
+ STATUS_MOVED_TEMPORARILY = 302,
+ STATUS_NOT_MODIFIED = 304,
+ STATUS_BAD_REQUEST = 400,
+ STATUS_UNAUTHORIZED = 401,
+ STATUS_FORBIDDEN = 403,
+ STATUS_NOT_FOUND = 404,
+ STATUS_INTERNAL_SERVER_ERROR = 500,
+ STATUS_NOT_IMPLEMENTED = 501,
+ STATUS_BAD_GATEWAY = 502,
+ STATUS_SERVICE_UNAVAILABLE = 503,
+ STATUS_INSUFFICIENT_DATA = 399
+ };
+
+ enum
+ {
+ MAX_STATUS_CODE = 599
+ };
+
+private:
+ // Singleton pattern is afoot here.
+ static const char *Reason[MAX_STATUS_CODE + 1];
+ static int instance_;
+ static ACE_SYNCH_MUTEX lock_;
+};
+
+#endif /* HTTP_HELPERS_H */
+
diff --git a/ACE/apps/JAWS/server/HTTP_Request.cpp b/ACE/apps/JAWS/server/HTTP_Request.cpp
new file mode 100644
index 00000000000..c2d4b7a3134
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Request.cpp
@@ -0,0 +1,664 @@
+// $Id$
+
+#include "ace/Message_Block.h"
+#include "HTTP_Request.h"
+#include "HTTP_Helpers.h"
+#include "HTTP_Config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_pwd.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(server, HTTP_Request, "$Id$")
+
+const char *const
+HTTP_Request::static_header_strings_[HTTP_Request::NUM_HEADER_STRINGS] =
+{
+ "Date",
+ "Pragma",
+ "Authorization",
+ "From",
+ "If-Modified-Since",
+ "Referrer",
+ "User-Agent",
+ "Allow",
+ "Content-Encoding",
+ "Content-Length",
+ "Content-Type",
+ "Expires",
+ "Last-Modified"
+};
+
+const char *const
+HTTP_Request::static_method_strings_[HTTP_Request::NUM_METHOD_STRINGS] =
+{
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT"
+};
+
+// For reasons of efficiency, this class expects buffer to be
+// null-terminated, and buflen does NOT include the \0.
+
+HTTP_Request::HTTP_Request (void)
+ : got_request_line_ (0),
+ method_ (0),
+ uri_ (0),
+ version_ (0),
+ path_ (0),
+ cgi_ (0),
+ cgi_env_ (0),
+ cgi_args_ (0),
+ query_string_ (0),
+ path_info_ (0),
+ header_strings_ (HTTP_Request::static_header_strings_),
+ method_strings_ (HTTP_Request::static_method_strings_)
+{
+
+ for (size_t i = 0;
+ i < HTTP_Request::NUM_HEADER_STRINGS;
+ i++)
+ this->headers_.recognize (this->header_strings_[i]);
+}
+
+HTTP_Request::~HTTP_Request (void)
+{
+ ACE_OS::free (this->method_);
+ ACE_OS::free (this->uri_);
+ ACE_OS::free (this->version_);
+ ACE_OS::free (this->path_);
+ ACE_OS::free (this->query_string_);
+ ACE_OS::free (this->path_info_);
+
+ delete [] this->cgi_env_;
+}
+
+int
+HTTP_Request::parse_request (ACE_Message_Block &mb)
+{
+ mb.wr_ptr ()[0] = '\0';
+
+ // Note that RFC 822 does not mention the maximum length of a header
+ // line. So in theory, there is no maximum length.
+
+ // In Apache, they assume that each header line should not exceed
+ // 8K.
+
+ int result = this->headers_.complete_header_line (mb.rd_ptr ());
+
+ if (result != 0)
+ {
+ if (!this->got_request_line ())
+ {
+ this->parse_request_line (mb.rd_ptr ());
+ while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0)
+ this->headers_.parse_header_line (mb.rd_ptr ());
+ }
+ else if (result > 0)
+ do
+ this->headers_.parse_header_line (mb.rd_ptr ());
+ while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0);
+ }
+
+ mb.wr_ptr (ACE_OS::strlen(mb.rd_ptr ()) - mb.length ());
+
+ if (this->headers_.end_of_headers ()
+ || (this->got_request_line () && this->version () == 0))
+ return this->init (mb.rd_ptr (), mb.length ());
+ else
+ return 0;
+}
+
+void
+HTTP_Request::parse_request_line (char *const request_line)
+{
+ char *ptr = request_line;
+ char *buf = request_line;
+ int offset = 1;
+
+ this->status_ = HTTP_Status_Code::STATUS_OK;
+
+ ptr = ACE_OS::strchr (request_line, '\n');
+
+ if (ptr > request_line && ptr[-1] == '\r')
+ ptr--, offset++;
+
+ if (ptr == request_line)
+ {
+ this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
+ return;
+ }
+
+ *ptr = '\0';
+ ptr += offset;
+
+ char *lasts = 0; // for strtok_r
+
+ // Get the request type.
+ this->got_request_line_ = 1;
+
+ if (this->method (ACE_OS::strtok_r (buf, " \t", &lasts))
+ && this->uri (ACE_OS::strtok_r (0, " \t", &lasts)))
+ {
+ this->type (this->method ());
+
+ if (this->version (ACE_OS::strtok_r (0, " \t", &lasts)) == 0
+ && this->type () != HTTP_Request::GET)
+ this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
+
+ if (this->path (this->uri ()) == 0)
+ this->status_ = HTTP_Status_Code::STATUS_NOT_FOUND;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) request %s %s %s parsed\n",
+ (this->method () ? this->method () : "-"),
+ (this->uri () ? this->uri () : "="),
+ (this->version () ? this->version () : "HTTP/0.9")));
+
+ ACE_OS::memmove (buf, ptr, ACE_OS::strlen (ptr)+1);
+}
+
+int
+HTTP_Request::init (char *const buffer,
+ int buflen)
+{
+ // Initialize these every time.
+ content_length_ = -1;
+
+ // Extract the data pointer.
+ data_ = buffer;
+ datalen_ = 0;
+
+ // Set the datalen
+ if (data_ != 0)
+ datalen_ = buflen;
+ else
+ datalen_ = 0;
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) init has initialized\n"));
+
+ return 1;
+}
+
+const char *
+HTTP_Request::method (void) const
+{
+ return this->method_;
+}
+
+const char *
+HTTP_Request::uri (void) const
+{
+ return this->uri_;
+}
+
+const char *
+HTTP_Request::version (void) const
+{
+ return this->version_;
+}
+
+const char *
+HTTP_Request::path (void) const
+{
+ return this->path_;
+}
+
+int
+HTTP_Request::cgi (void) const
+{
+ return this->cgi_;
+}
+
+const char **
+HTTP_Request::cgi_env (void) const
+{
+ return (const char **)this->cgi_env_;
+}
+
+const char *
+HTTP_Request::cgi_args (void) const
+{
+ return this->cgi_args_;
+}
+
+const char *
+HTTP_Request::query_string (void) const
+{
+ return this->query_string_;
+}
+
+const char *
+HTTP_Request::path_info (void) const
+{
+ return this->path_info_;
+}
+
+int
+HTTP_Request::got_request_line (void) const
+{
+ return this->got_request_line_;
+}
+
+int
+HTTP_Request::type (void) const
+{
+ return type_;
+}
+
+const Headers &
+HTTP_Request::headers (void) const
+{
+ return this->headers_;
+}
+
+const char *
+HTTP_Request::header_strings (int index) const
+{
+ const char *hs = 0;
+
+ if (0 <= index && index < NUM_HEADER_STRINGS)
+ hs = this->header_strings_[index];
+
+ return hs;
+}
+
+const char *
+HTTP_Request::header_values (int index) const
+{
+ const char *hs = 0;
+ const char *hv = 0;
+
+ if (0 <= index && index < NUM_HEADER_STRINGS)
+ {
+ hs = this->header_strings_[index];
+ hv = this->headers_[hs].value ();
+ }
+
+ return hv;
+}
+
+char *
+HTTP_Request::data (void)
+{
+ return data_;
+}
+
+int
+HTTP_Request::data_length (void)
+{
+ return datalen_;
+}
+
+int
+HTTP_Request::content_length (void)
+{
+ if (this->content_length_ == -1)
+ {
+ const char * clv = this->headers_["Content-length"].value ();
+ this->content_length_ = (clv ? ACE_OS::atoi (clv) : 0);
+ }
+
+ return this->content_length_;
+}
+
+int
+HTTP_Request::status (void)
+{
+ return this->status_;
+}
+
+const char *
+HTTP_Request::status_string (void)
+{
+ return HTTP_Status_Code::instance ()[this->status_];
+}
+
+void
+HTTP_Request::dump (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "%s command.\n"
+ "filename is %s,"
+ " length of the file is %d,"
+ " data string is %s,"
+ " datalen is %d,"
+ " status is %d, which is %s\n\n",
+ this->method () ? this->method () : "EMPTY",
+ this->uri () ? this->uri () : "EMPTY",
+ this->content_length (),
+ this->data () ? this->data () : "EMPTY",
+ this->data_length (),
+ this->status (),
+ this->status_string ()));
+}
+
+const char *
+HTTP_Request::method (const char *method_string)
+{
+ if (this->method_)
+ ACE_OS::free (this->method_);
+
+ if (method_string == 0)
+ {
+ this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
+ this->method_ = 0;
+ }
+ else
+ this->method_ = ACE_OS::strdup (method_string);
+
+ return this->method_;
+}
+
+const char *
+HTTP_Request::uri (char *uri_string)
+{
+ if (this->uri_)
+ ACE_OS::free (this->uri_);
+
+ if (uri_string == 0)
+ {
+ this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
+ this->uri_ = 0;
+ }
+ else
+ {
+ this->uri_ = ACE_OS::strdup (uri_string);
+ this->cgi (this->uri_);
+ HTTP_Helper::HTTP_decode_string (this->uri_);
+ }
+
+ return this->uri_;
+}
+
+const char *
+HTTP_Request::version (const char *version_string)
+{
+ if (this->version_)
+ ACE_OS::free (this->version_);
+
+ if (version_string)
+ this->version_ = ACE_OS::strdup (version_string);
+ else
+ this->version_ = 0;
+
+ return this->version_;
+}
+
+int
+HTTP_Request::type (const char *type_string)
+{
+ this->type_ = HTTP_Request::NO_TYPE;
+
+ if (type_string == 0)
+ return this->type_;
+
+ for (size_t i = 0;
+ i < HTTP_Request::NUM_METHOD_STRINGS;
+ i++)
+
+ if (ACE_OS::strcmp (type_string, this->method_strings_[i]) == 0)
+ {
+ this->type_ = i;
+ break;
+ }
+
+ if (this->type_ == HTTP_Request::NO_TYPE)
+ this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
+
+ return this->type_;
+}
+
+int
+HTTP_Request::cgi (char *uri_string)
+{
+ this->cgi_ = 0;
+ this->cgi_env_ = 0;
+ this->cgi_args_ = 0;
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi (%s)\n", uri_string));
+
+ if (uri_string == 0 || ACE_OS::strlen (uri_string) == 0)
+ return 0;
+
+ // There are 2 cases where a file could be a CGI script
+ //
+ // (1) the file has a CGI extension.
+ // (2) the file resides in a CGI bin directory.
+
+ char *extra_path_info = 0;
+ if (this->cgi_in_path (uri_string, extra_path_info)
+ || this->cgi_in_extension (uri_string, extra_path_info))
+ {
+ cgi_args_and_env (extra_path_info);
+
+ if (extra_path_info)
+ {
+ this->path_info_ = ACE_OS::strdup (extra_path_info);
+ HTTP_Helper::HTTP_decode_string (this->path_info_);
+ *extra_path_info = '\0';
+ }
+ }
+
+ return this->cgi_;
+}
+
+int
+HTTP_Request::cgi_in_path (char *uri_string, char *&extra_path_info)
+{
+ char *cgi_path;
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_path (%s)\n",
+ uri_string));
+
+ if (HTTP_Config::instance ()->cgi_path ())
+ cgi_path = ACE_OS::strdup (HTTP_Config::instance ()->cgi_path ());
+ else
+ cgi_path = ACE_OS::strdup ("");
+
+ // error checking considered helpful!
+ if (cgi_path == 0)
+ return 0;
+
+ char *lasts = 0;
+ char *cgi_path_next = ACE_OS::strtok_r (cgi_path, ":", &lasts);
+
+ if (cgi_path_next)
+ do
+ {
+ int len = ACE_OS::strlen (cgi_path_next);
+
+ // match path to cgi path
+ int in_cgi_path = 0;
+
+ if (*cgi_path_next == '/')
+ {
+ // cgi path next points to an ``absolute'' path
+ extra_path_info = uri_string;
+ in_cgi_path =
+ (ACE_OS::strncmp (extra_path_info, cgi_path_next, len) == 0);
+ }
+ else
+ {
+ // cgi path next points to a ``relative'' path
+ extra_path_info = ACE_OS::strstr (uri_string, cgi_path_next);
+ in_cgi_path = (extra_path_info != 0);
+ }
+
+ if (in_cgi_path)
+ {
+ if (extra_path_info[len] == '/')
+ {
+ this->cgi_ = 1;
+ extra_path_info += len;
+
+ // move past the executable name
+ do
+ extra_path_info++;
+ while (*extra_path_info != '/'
+ && *extra_path_info != '?'
+ && *extra_path_info != '\0');
+
+ if (*extra_path_info == '\0')
+ extra_path_info = 0;
+
+ break;
+ }
+ }
+ extra_path_info = 0;
+
+ cgi_path_next = ACE_OS::strtok_r (0, ":", &lasts);
+ }
+ while (cgi_path_next);
+
+ ACE_OS::free (cgi_path);
+
+ return this->cgi_;
+}
+
+int
+HTTP_Request::cgi_in_extension (char *uri_string, char *&extra_path_info)
+{
+ extra_path_info = ACE_OS::strstr (uri_string, ".cgi");
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_extension (%s)\n",
+ uri_string));
+
+ while (extra_path_info != 0)
+ {
+ extra_path_info += 4;
+ // skip past ``.cgi''
+
+ switch (*extra_path_info)
+ {
+ case '\0':
+ extra_path_info = 0;
+ break;
+ case '/':
+ case '?':
+ break;
+ default:
+ extra_path_info = ACE_OS::strstr (extra_path_info, ".cgi");
+ continue;
+ }
+ this->cgi_ = 1;
+ break;
+ }
+
+ return this->cgi_;
+}
+
+void
+HTTP_Request::cgi_args_and_env (char *&extra_path_info)
+{
+ char *cgi_question = 0;
+
+ if (extra_path_info)
+ cgi_question = ACE_OS::strchr (extra_path_info, '?');
+
+ if (extra_path_info == cgi_question)
+ extra_path_info = 0;
+
+ if (cgi_question)
+ {
+ *cgi_question++ = '\0';
+
+ if (*cgi_question != '\0')
+ {
+ // We need the ``original'' QUERY_STRING for the
+ // environment. We will substitute '+'s for spaces in the
+ // other copy.
+
+ this->query_string_ = ACE_OS::strdup (cgi_question);
+
+ char *ptr = cgi_question;
+ int count = 0;
+ do
+ if (*ptr == '+')
+ *ptr = ' ';
+ else if (*ptr == '&' || *ptr == '=')
+ count++;
+ while (*++ptr);
+
+ count++;
+
+ if (ACE_OS::strchr (cgi_question, '='))
+ {
+ ACE_NEW (this->cgi_env_, char *[count+1]);
+
+ int i = 0;
+ ptr = cgi_question;
+ do
+ {
+ this->cgi_env_ [i++] = ptr;
+
+ while (*ptr++)
+ if (*ptr == '&' || *ptr == '=')
+ *ptr = '\0';
+
+ HTTP_Helper::HTTP_decode_string (this->cgi_env_[i-1]);
+ }
+ while (i < count);
+
+ this->cgi_env_[count] = 0;
+ }
+ else
+ {
+ this->cgi_args_ = cgi_question;
+ HTTP_Helper::HTTP_decode_string (cgi_question);
+ }
+ }
+ }
+}
+
+const char *
+HTTP_Request::path (const char *uri_string)
+{
+ char const *file_name = uri_string;
+ char buf[MAXPATHLEN + 1];
+ buf[0] = '\0';
+
+ if (file_name == 0) return 0;
+
+ if (*file_name == '/')
+ {
+ file_name++;
+ if (*file_name == '~')
+ {
+ char *ptr = buf;
+
+ while (*++file_name && *file_name != '/')
+ *ptr++ = *file_name;
+
+ *ptr = '\0';
+
+ if (ptr == buf)
+ ACE_OS::strcpy (buf, ACE_OS::getenv ("HOME"));
+ else
+ {
+#if !defined (ACE_WIN32) && !defined (VXWORKS)
+ char pw_buf[BUFSIZ];
+ struct passwd pw_struct;
+ if (ACE_OS::getpwnam_r (buf, &pw_struct, pw_buf, sizeof (pw_buf))
+ == 0)
+ return 0;
+ ACE_OS::strcpy (buf, pw_struct.pw_dir);
+#endif /* NOT ACE_WIN32 AND NOT VXWORKS */
+ }
+
+ ACE_OS::strcat (buf, "/");
+ ACE_OS::strcat (buf, HTTP_Config::instance ()->user_dir ());
+ ACE_OS::strcat (buf, file_name);
+ }
+ else
+ {
+ // With a starting '/' but no '~'
+ ACE_OS::strcat (buf, HTTP_Config::instance ()->document_root ());
+ ACE_OS::strcat (buf, file_name - 1);
+ }
+ }
+
+ if (*buf != '\0')
+ this->path_ = ACE_OS::strdup (buf);
+
+ return this->path_;
+}
diff --git a/ACE/apps/JAWS/server/HTTP_Request.h b/ACE/apps/JAWS/server/HTTP_Request.h
new file mode 100644
index 00000000000..3581d802540
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Request.h
@@ -0,0 +1,202 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// HTTP_Request.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef HTTP_REQUEST_H
+#define HTTP_REQUEST_H
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "Parse_Headers.h"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+class ACE_Message_Block;
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+class HTTP_Request
+ // = TITLE
+ // This parses the client request of an HTTP transaction.
+ //
+ // = DESCRIPTION
+{
+public:
+ HTTP_Request (void);
+ // Default construction.
+
+ ~HTTP_Request (void);
+ // Destructor.
+
+ int parse_request (ACE_Message_Block &mb);
+ // parse an incoming request
+
+ void parse_request_line (char *const request_line);
+ // the first line of a request is the request line, which is of the
+ // form: METHOD URI VERSION.
+
+ int init (char *const buffer,
+ int buflen);
+ // Initialize the request object. This will parse the buffer and
+ // prepare for the accessors.
+
+public:
+ // = The Accessors.
+
+ const char *method (void) const;
+ // HTTP request method
+
+ const char *uri (void) const;
+ // HTTP request uri
+
+ const char *version (void) const;
+ // HTTP request version
+
+ const char *path (void) const;
+ // The HTTP request uri translated into a server filename path
+
+ int cgi (void) const;
+ // TRUE of the request is a cgi request
+
+ const char *cgi_args (void) const;
+ // The arguments to the cgi request
+
+ const char **cgi_env (void) const;
+ // The environment variables passed to the CGI request
+
+ const char *query_string (void) const;
+ // The cgi request query string
+
+ const char *path_info (void) const;
+ // The cgi request path information
+
+ int type (void) const;
+ // The type of the HTTP request
+
+ const Headers &headers (void) const;
+ // The headers that were parsed from the request
+
+ const char *header_strings (int index) const;
+ // Header strings stored
+
+ const char *header_values (int index) const;
+ // Values associated with the header strings
+
+ char *data (void);
+ // The buffer into which request data is read
+
+ int data_length (void);
+ // The length of the request data
+
+ int content_length (void);
+ // The length of incoming content if any
+
+ int status (void);
+ // Current status of the incoming request
+
+ const char *status_string (void);
+ // A string describing the state of the incoming request
+
+ void dump (void);
+ // Dump the state of the request.
+
+ enum
+ {
+ NO_TYPE = -1,
+ GET = 0,
+ HEAD,
+ POST,
+ PUT,
+ NUM_METHOD_STRINGS
+ };
+ // Values for request type
+
+ enum
+ {
+ DATE = 0,
+ PRAGMA,
+ AUTHORIZATION,
+ FROM,
+ IF_MODIFIED_SINCE,
+ REFERRER,
+ USER_AGENT,
+ ALLOW,
+ CONTENT_ENCODING,
+ CONTENT_LENGTH,
+ CONTENT_TYPE,
+ EXPIRES,
+ LAST_MODIFIED,
+ NUM_HEADER_STRINGS
+ };
+ // Header strings
+
+private:
+ // = Private Accessors which can set values
+ const char *method (const char *method_string);
+ const char *uri (char *uri_string);
+ const char *version (const char *version_string);
+ const char *path (const char *uri_string);
+
+ int cgi (char *uri_string);
+ // determine if the given URI is a CGI program.
+
+ int cgi_in_path (char *uri_string, char *&extra_path_info);
+ // determine if the given URI resides in a cgi-bin directory
+
+ int cgi_in_extension (char *uri_string, char *&extra_path_info);
+ // determine if the given URI contains a cgi extension
+
+ void cgi_args_and_env (char *&extra_path_info);
+ // set the arguments and environment for the cgi program
+
+ int type (const char *type_string);
+
+private:
+ int got_request_line (void) const;
+
+private:
+ int got_request_line_;
+ Headers headers_;
+
+ char *method_;
+ char *uri_;
+ char *version_;
+ char *path_;
+
+ int cgi_;
+ char **cgi_env_;
+ char *cgi_args_;
+
+ char *query_string_;
+ char *path_info_;
+
+ const char * const *const header_strings_;
+ static const char *const static_header_strings_[NUM_HEADER_STRINGS];
+
+ const char * const *const method_strings_;
+ static const char *const static_method_strings_[NUM_METHOD_STRINGS];
+
+ char *data_;
+ int datalen_;
+ int content_length_;
+ char *filename_;
+ int status_;
+ int type_;
+};
+
+#endif /* HTTP_REQUEST_H */
diff --git a/ACE/apps/JAWS/server/HTTP_Response.cpp b/ACE/apps/JAWS/server/HTTP_Response.cpp
new file mode 100644
index 00000000000..5f5b036989e
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Response.cpp
@@ -0,0 +1,388 @@
+// $Id$
+
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/os_include/os_ctype.h"
+#include "ace/Process.h"
+#include "ace/Mem_Map.h"
+#include "ace/Log_Msg.h"
+
+#include "HTTP_Response.h"
+#include "HTTP_Request.h"
+#include "HTTP_Helpers.h"
+#include "HTTP_Config.h"
+#include "IO.h"
+
+ACE_RCSID(server, HTTP_Response, "$Id$")
+
+#if defined (ACE_JAWS_BASELINE)
+static char * const EMPTY_HEADER = "";
+#else
+static const char * const EMPTY_HEADER = "";
+#endif /* ACE_JAWS_BASELINE */
+
+HTTP_Response::HTTP_Response (JAWS_IO &io, HTTP_Request &request)
+ : io_(io), request_(request)
+{
+}
+
+HTTP_Response::HTTP_Response (HTTP_Request &request, JAWS_IO &io)
+ : io_(io), request_(request)
+{
+}
+
+HTTP_Response::~HTTP_Response (void)
+{
+#if defined (ACE_JAWS_BASELINE)
+ if (this->HTTP_HEADER != EMPTY_HEADER)
+ delete [] this->HTTP_HEADER;
+ // The [] is important. Without it, there was a huge memory leak!
+#endif /* ACE_JAWS_BASELINE */
+}
+
+void
+HTTP_Response::process_request(HTTP_Response &response)
+{
+ response.process_request();
+}
+
+void
+HTTP_Response::process_request (void)
+{
+ ACE_DEBUG ((LM_DEBUG, " (%t) processing request: %s\n",
+ this->request_.status_string ()));
+
+ switch (this->request_.status ())
+ {
+ case HTTP_Status_Code::STATUS_OK :
+
+ if (this->request_.cgi ())
+ {
+ this->cgi_response ();
+ }
+ else
+ {
+ this->normal_response ();
+ }
+
+ break;
+
+ default:
+ this->error_response (this->request_.status (),
+ this->request_.status_string ());
+ }
+}
+
+void
+HTTP_Response::error_response (int status_code, const char *log_message)
+{
+ ACE_DEBUG ((LM_DEBUG, "(%t) [%s %s %s] %s\n",
+ this->request_.method () ? this->request_.method () : "-",
+ this->request_.uri () ? this->request_.uri () : "-",
+ this->request_.version() ? this->request_.version () : "-",
+ log_message ? log_message : "-"));
+
+ static char const error_header1[] =
+ "%s %d %s\r\n"
+ "Server: JAWS/1.0prebeta\r\n"
+ "Content-type: text/html\r\n"
+ "Content-length: %d\r\n"
+ "\r\n"
+ "%s"
+ ;
+
+ static char const error_header2[] =
+ "%s %d %s\r\n"
+ "Server: JAWS/1.0prebeta\r\n"
+ "WWW-Authenticate: Basic realm=\"JAWS_authorization\"\r\n"
+ "Content-type: text/html\r\n"
+ "Content-length: %d\r\n"
+ "\r\n"
+ "%s"
+ ;
+
+ static char const error_message[] =
+ "<html>\n"
+ "<head><title>Server error message</title></head>\n"
+ "<body>\n"
+ "<h1>Error %d: %s</h1>\n"
+ "The request could not be completed because:\n %s\n"
+ "</body>\n"
+ "</html>\n"
+ ;
+
+
+ char *buf;
+ char buf1[4 * BUFSIZ];
+ char buf2[BUFSIZ];
+
+ int length;
+ const char *error_header = error_header1;
+
+ if (status_code == HTTP_Status_Code::STATUS_UNAUTHORIZED)
+ error_header = error_header2;
+
+ length =
+ ACE_OS::sprintf (buf2, error_message,
+ status_code, HTTP_Status_Code::instance ()[status_code],
+ log_message);
+
+ if (this->request_.version () == 0
+ || ACE_OS::strcmp ("HTTP/0.9", this->request_.version ()) == 0)
+ buf = buf2;
+ else
+ {
+ length =
+ ACE_OS::sprintf (buf1, error_header,
+ this->request_.version(), status_code,
+ HTTP_Status_Code::instance ()[status_code],
+ length,
+ buf2);
+ buf = buf1;
+ }
+
+ this->io_.send_error_message (buf, length);
+}
+
+void
+HTTP_Response::normal_response (void)
+{
+ const char *hv = 0;;
+
+ ACE_DEBUG ((LM_DEBUG, " (%t) %s request for %s [%s], version %s\n",
+ request_.method (), request_.uri (), request_.path (),
+ (request_.version () ? request_.version () : "HTTP/0.9")));
+
+ switch (this->request_.type ())
+ {
+ case HTTP_Request::GET :
+
+ this->build_headers ();
+ this->io_.transmit_file (this->request_.path (),
+ this->HTTP_HEADER,
+ this->HTTP_HEADER_LENGTH,
+ this->HTTP_TRAILER,
+ this->HTTP_TRAILER_LENGTH);
+ break;
+
+ case HTTP_Request::HEAD :
+ this->build_headers ();
+ this->io_.send_confirmation_message (this->HTTP_HEADER,
+ this->HTTP_HEADER_LENGTH);
+ break;
+
+ case HTTP_Request::POST :
+ // What to do here?
+ // Standard says this is implementation dependent.
+ // Examples: annotations, page updates, etc.
+ // This may be a good place to stick CORBA stuff,
+ // and mobile code.
+ this->error_response (HTTP_Status_Code::STATUS_NOT_IMPLEMENTED,
+ "Requested method is not implemented.");
+ break;
+
+ case HTTP_Request::PUT :
+ // Only commit to this if we can authenticate it
+
+ // if there is no Authentication: header on the incoming request,
+ // deny it
+ hv = this->request_.headers ()["Authorization"].value ();
+ if (hv == 0 || *hv == '\0')
+ this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
+ "Unauthorized to use PUT method");
+ else if (ACE_OS::strncmp (hv, "Basic ", 6) != 0)
+ // ``6'' is the length of the string "Basic "
+ this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
+ "Unknown authroization method");
+ else
+ {
+ ACE_Mem_Map mmapfile;
+ const char *hvv = hv + 6;
+ // Skip past the string "Basic "
+ char *buf = new char [ACE_OS::strlen (hv)];
+ char *auth
+ = HTTP_Helper::HTTP_decode_base64 (ACE_OS::strcpy (buf, hvv));
+
+ if (mmapfile.map (ACE_TEXT ("jaws.auth")) != -1
+ && auth != 0
+ && ACE_OS::strstr((const char *) mmapfile.addr (), auth) != 0)
+ this->io_.receive_file (this->request_.path (),
+ this->request_.data (),
+ this->request_.data_length (),
+ this->request_.content_length ());
+ else
+ this->error_response (HTTP_Status_Code::STATUS_UNAUTHORIZED,
+ "Invalid authorization attempt");
+ delete [] buf;
+ }
+ break;
+
+ default :
+ this->error_response (HTTP_Status_Code::STATUS_NOT_IMPLEMENTED,
+ "Requested method is not implemented.");
+ }
+}
+
+
+void
+HTTP_Response::cgi_response (void)
+{
+ ACE_Process_Options cgi_options;
+
+ if (this->request_.cgi_args ())
+ cgi_options.command_line ("%s %s",
+ this->request_.path (),
+ this->request_.cgi_args ());
+ else
+ cgi_options.command_line ("%s", this->request_.path ());
+
+ // Build environment variables
+ cgi_options.setenv ("SERVER_SOFTWARE", "%s", "JAWS/1.0");
+ cgi_options.setenv ("SERVER_NAME", "%s", "localhost");
+ cgi_options.setenv ("GATEWAY_INTERFACE", "%s", "CGI/1.1");
+
+ cgi_options.setenv ("SERVER_PROTOCOL", "%s",
+ this->request_.version ()
+ ? this->request_.version ()
+ : "HTTP/0.9");
+ cgi_options.setenv ("SERVER_PORT", "%d", 5432);
+
+ cgi_options.setenv ("REQUEST_METHOD", "%s", this->request_.method ());
+
+ if (this->request_.path_info ())
+ {
+ cgi_options.setenv ("PATH_INFO", "%s",
+ this->request_.path_info ());
+ cgi_options.setenv ("PATH_TRANSLATED",
+ "%s/%s",
+ HTTP_Config::instance ()->document_root (),
+ this->request_.path_info ());
+ }
+
+ cgi_options.setenv ("SCRIPT_NAME",
+ "%s",
+ this->request_.uri ());
+
+ if (this->request_.query_string ())
+ cgi_options.setenv ("QUERY_STRING",
+ "%s",
+ this->request_.query_string ());
+
+ if (this->request_.cgi_env ())
+ for (size_t i = 0; this->request_.cgi_env ()[i]; i += 2)
+ cgi_options.setenv (this->request_.cgi_env ()[i],
+ "%s",
+ this->request_.cgi_env ()[i+1]);
+
+ char buf[BUFSIZ];
+ char *p, *q;
+ ACE_OS::strcpy (buf, "HTTP_");
+ p = q = buf + ACE_OS::strlen (buf);
+
+ for (size_t i = 0; i < HTTP_Request::NUM_HEADER_STRINGS; i++)
+ {
+ int j = 0;
+
+ for (char c; (c = this->request_.header_strings (i)[j++]) != '\0'; )
+ if (isalpha (c))
+ *q++ = toupper (c);
+ else if (c == '-')
+ *q++ = '_';
+ else
+ *q++ = c;
+
+ *q = '\0';
+
+ const char *hv = this->request_.header_values (i);
+
+ if (hv && *hv)
+ cgi_options.setenv (buf, "%s", hv);
+ q = p;
+ }
+
+ cgi_options.set_handles (this->io_.handle (),
+ this->io_.handle (),
+ this->io_.handle ());
+
+ this->build_headers ();
+ this->io_.send_confirmation_message (this->HTTP_HEADER,
+ this->HTTP_HEADER_LENGTH);
+ // ACE::send (this->io_.handle (),
+ // this->HTTP_HEADER, this->HTTP_HEADER_LENGTH);
+
+ // Exec the CGI program.
+ ACE_Process cgi_process;
+ cgi_process.spawn (cgi_options);
+ // cgi_process.wait ();
+}
+
+void
+HTTP_Response::build_headers (void)
+{
+ // At this point, we should really determine the type of request
+ // this is, and build the appropriate header.
+
+ // Let's assume this is HTML for now. Unless the request is CGI,
+ // then do not include content-* headers.
+
+ if (this->request_.version () == 0
+ || ACE_OS::strcmp ("HTTP/0.9", this->request_.version ()) == 0)
+ {
+ HTTP_HEADER = EMPTY_HEADER;
+ HTTP_HEADER_LENGTH = 0;
+ }
+ else
+ {
+#if defined (ACE_JAWS_BASELINE)
+ HTTP_HEADER = new char[BUFSIZ * 4];
+
+ // We assume that at this point everything is OK
+ HTTP_HEADER_LENGTH =
+ ACE_OS::sprintf (HTTP_HEADER, "%s", "HTTP/1.0 200 OK\r\n");
+
+ char date_ptr [40];
+ // 40 bytes is the maximum length needed to store the date
+
+ if (HTTP_Helper::HTTP_date (date_ptr) != 0)
+ HTTP_HEADER_LENGTH +=
+ ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
+ "Date: %s\r\n", date_ptr);
+
+ if (! this->request_.cgi ()) {
+ HTTP_HEADER_LENGTH +=
+ ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
+ "Content-type: %s\r\n",
+ "text/html");
+
+ struct stat file_stat;
+ // If possible, add the Content-length field to the header.
+ // @@ Note that using 'ACE_OS::stat' is a hack. Normally, a
+ // web browser will have a 'virtual' file system. In a VFS,
+ // 'stat' might not reference the correct location.
+ if ((this->request_.type () == HTTP_Request::GET) &&
+ (ACE_OS::stat (this->request_.path (), &file_stat) == 0))
+ {
+ HTTP_HEADER_LENGTH +=
+ ACE_OS::sprintf (HTTP_HEADER+HTTP_HEADER_LENGTH,
+ "Content-length: %u\r\n", file_stat.st_size);
+ }
+
+ // Complete header with empty line and adjust header length.
+ HTTP_HEADER[HTTP_HEADER_LENGTH++] = '\r';
+ HTTP_HEADER[HTTP_HEADER_LENGTH++] = '\n';
+ }
+#else
+ if (! this->request_.cgi ())
+ HTTP_HEADER = "HTTP/1.0 200 OK\r\n"
+ "Content-type: text/html\r\n\r\n";
+ else
+ HTTP_HEADER = "HTTP/1.0 200 OK\r\n";
+
+ HTTP_HEADER_LENGTH = ACE_OS::strlen (HTTP_HEADER);
+
+#endif /* ACE_JAWS_BASELINE */
+ }
+
+ HTTP_TRAILER = "";
+ HTTP_TRAILER_LENGTH = 0;
+}
diff --git a/ACE/apps/JAWS/server/HTTP_Response.h b/ACE/apps/JAWS/server/HTTP_Response.h
new file mode 100644
index 00000000000..2bd8d21fbc0
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Response.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// HTTP_Response.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef HTTP_RESPONSE_H
+#define HTTP_RESPONSE_H
+
+class JAWS_IO;
+class HTTP_Request;
+
+class HTTP_Response
+ // = TITLE
+ // Abstraction for HTTP responses.
+ //
+ // = DESCRIPTION
+ // Provides an encapsulation of responses to HTTP requests.
+ // For instance, given an HTTP GET request, it will produce
+ // header and body suitable for returning to the client who made
+ // the request.
+{
+public:
+ HTTP_Response (JAWS_IO &io,
+ HTTP_Request &request);
+ HTTP_Response (HTTP_Request &request, JAWS_IO &io);
+ ~HTTP_Response (void);
+
+ void process_request (void);
+ // This is called by the handler to initiate a response.
+
+ void error_response (int status,
+ const char *log_message);
+ // This returns an error response for cases where there is a problem
+ // with the request, logging the log_message.
+
+private:
+
+ void normal_response (void);
+ // Called by process_request when the request is a normal request.
+
+ void cgi_response (void);
+ // Called by process_request when the request is a cgi request.
+
+private:
+
+ static void process_request (HTTP_Response &response);
+ // static version of process_request, just in case.
+
+ void build_headers (void);
+ // creates the appropriate header information for responses.
+
+private:
+ JAWS_IO &io_;
+ HTTP_Request &request_;
+ // The IO and Request objects associated with this re
+
+#if defined (ACE_JAWS_BASELINE)
+ char *HTTP_HEADER;
+#else
+ const char *HTTP_HEADER;
+#endif
+ const char *HTTP_TRAILER;
+ int HTTP_HEADER_LENGTH;
+ int HTTP_TRAILER_LENGTH;
+ // HTTP Headers and trailers.
+};
+
+#endif /* HTTP_RESPONSE_H */
diff --git a/ACE/apps/JAWS/server/HTTP_Server.cpp b/ACE/apps/JAWS/server/HTTP_Server.cpp
new file mode 100644
index 00000000000..86ffea0542a
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Server.cpp
@@ -0,0 +1,431 @@
+// $Id$
+
+#ifndef ACE_BUILD_SVC_DLL
+#define ACE_BUILD_SVC_DLL
+#endif /* ACE_BUILD_SVC_DLL */
+
+#include "ace/OS_NS_string.h"
+#include "ace/Get_Opt.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/LOCK_SOCK_Acceptor.h"
+#include "ace/Proactor.h"
+#include "ace/Signal.h"
+#include "ace/Auto_Ptr.h"
+
+#include "IO.h"
+#include "HTTP_Server.h"
+
+ACE_RCSID(server, HTTP_Server, "$Id$")
+
+// class is overkill
+class JAWS
+{
+public:
+ enum
+ {
+ JAWS_POOL = 0,
+ JAWS_PER_REQUEST = 1
+ };
+
+ enum
+ {
+ JAWS_SYNCH = 0,
+ JAWS_ASYNCH = 2
+ };
+};
+
+void
+HTTP_Server::parse_args (int argc, ACE_TCHAR *argv[])
+{
+ int c;
+ int thr_strategy = 0;
+ int io_strategy = 0;
+ const ACE_TCHAR *prog = argc > 0 ? argv[0] : ACE_TEXT ("HTTP_Server");
+
+ // Set some defaults
+ this->port_ = 0;
+ this->threads_ = 0;
+ this->backlog_ = 0;
+ this->throttle_ = 0;
+ this->caching_ = true;
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:n:t:i:b:c:"));
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'p':
+ this->port_ = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ this->threads_ = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't':
+ // POOL -> thread pool
+ // PER_REQUEST -> thread per request
+ // THROTTLE -> thread per request with throttling
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("POOL")) == 0)
+ thr_strategy = JAWS::JAWS_POOL;
+ else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("PER_REQUEST")) == 0)
+ {
+ thr_strategy = JAWS::JAWS_PER_REQUEST;
+ this->throttle_ = 0;
+ }
+ else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THROTTLE")) == 0)
+ {
+ thr_strategy = JAWS::JAWS_PER_REQUEST;
+ this->throttle_ = 1;
+ }
+ break;
+ case 'f':
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_BOUND")) == 0)
+ {
+ // What happened here?
+ }
+ else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DAEMON")) == 0)
+ {
+ }
+ else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DETACHED")) == 0)
+ {
+ }
+ case 'i':
+ // SYNCH -> synchronous I/O
+ // ASYNCH -> asynchronous I/O
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("SYNCH")) == 0)
+ io_strategy = JAWS::JAWS_SYNCH;
+ else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("ASYNCH")) == 0)
+ io_strategy = JAWS::JAWS_ASYNCH;
+ break;
+ case 'b':
+ this->backlog_ = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("NO_CACHE")) == 0)
+ this->caching_ = false;
+ else
+ this->caching_ = true;
+ break;
+ default:
+ break;
+ }
+
+ // No magic numbers.
+ if (this->port_ <= 0)
+ this->port_ = 5432;
+ if (this->threads_ <= 0)
+ this->threads_ = 5;
+ // Don't use number of threads as default
+ if (this->backlog_ <= 0)
+ this->backlog_ = this->threads_;
+
+ this->strategy_ = thr_strategy | io_strategy;
+
+ ACE_UNUSED_ARG (prog);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("in HTTP_Server::init, %s port = %d, ")
+ ACE_TEXT ("number of threads = %d\n"),
+ prog, this->port_, this->threads_));
+}
+
+int
+HTTP_Server::init (int argc, ACE_TCHAR *argv[])
+ // Document this function
+{
+ // Ignore signals generated when a connection is broken unexpectedly.
+ ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE);
+ ACE_UNUSED_ARG (sig);
+
+ // Parse arguments which sets the initial state.
+ this->parse_args (argc, argv);
+
+ //If the IO strategy is synchronous (SYNCH case), then choose a handler
+ //factory based on the desired caching scheme
+ HTTP_Handler_Factory *f = 0;
+
+ if (this->strategy_ != (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH))
+ if (this->caching_)
+ ACE_NEW_RETURN (f, Synch_HTTP_Handler_Factory (), -1);
+ else
+ ACE_NEW_RETURN (f, No_Cache_Synch_HTTP_Handler_Factory (), -1);
+
+ //NOTE: At this point f better not be a NULL pointer,
+ //so please do not change the ACE_NEW_RETURN macros unless
+ //you know what you are doing
+ ACE_Auto_Ptr<HTTP_Handler_Factory> factory (f);
+
+
+ // Choose what concurrency strategy to run.
+ switch (this->strategy_)
+ {
+ case (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH) :
+ return this->asynch_thread_pool ();
+
+ case (JAWS::JAWS_PER_REQUEST | JAWS::JAWS_SYNCH) :
+ return this->thread_per_request (*factory.get ());
+
+ case (JAWS::JAWS_POOL | JAWS::JAWS_SYNCH) :
+ default:
+ return this->synch_thread_pool (*factory.get ());
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+
+int
+HTTP_Server::fini (void)
+{
+ this->tm_.close ();
+ return 0;
+}
+
+
+int
+HTTP_Server::synch_thread_pool (HTTP_Handler_Factory &factory)
+{
+ // Main thread opens the acceptor
+ if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1,
+ PF_INET, this->backlog_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("HTTP_Acceptor::open")), -1);
+
+ // Create a pool of threads to handle incoming connections.
+ Synch_Thread_Pool_Task t (this->acceptor_, this->tm_, this->threads_, factory);
+
+ this->tm_.wait ();
+ return 0;
+}
+
+Synch_Thread_Pool_Task::Synch_Thread_Pool_Task (HTTP_Acceptor &acceptor,
+ ACE_Thread_Manager &tm,
+ int threads,
+ HTTP_Handler_Factory &factory)
+ : ACE_Task<ACE_NULL_SYNCH> (&tm),
+ acceptor_ (acceptor),
+ factory_ (factory)
+{
+ if (this->activate (THR_DETACHED | THR_NEW_LWP, threads) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Synch_Thread_Pool_Task::open")));
+}
+
+int
+Synch_Thread_Pool_Task::svc (void)
+{
+ // Creates a factory of HTTP_Handlers binding to synchronous I/O strategy
+ //Synch_HTTP_Handler_Factory factory;
+
+ for (;;)
+ {
+ ACE_SOCK_Stream stream;
+
+ // Lock in this accept. When it returns, we have a connection.
+ if (this->acceptor_.accept (stream) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"),
+ ACE_TEXT ("HTTP_Acceptor::accept")), -1);
+
+ ACE_Message_Block *mb;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1),
+ -1);
+
+ // Create an HTTP Handler to handle this request
+ HTTP_Handler *handler = this->factory_.create_http_handler ();
+ handler->open (stream.get_handle (), *mb);
+ // Handler is destroyed when the I/O puts the Handler into the
+ // done state.
+
+ mb->release ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) in Synch_Thread_Pool_Task::svc, recycling\n")));
+ }
+
+ ACE_NOTREACHED(return 0);
+}
+
+int
+HTTP_Server::thread_per_request (HTTP_Handler_Factory &factory)
+{
+ int grp_id = -1;
+
+ // thread per request
+ // Main thread opens the acceptor
+ if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1,
+ PF_INET, this->backlog_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("HTTP_Acceptor::open")), -1);
+
+ ACE_SOCK_Stream stream;
+
+ // When we are throttling, this is the amount of time to wait before
+ // checking for runnability again.
+ const ACE_Time_Value wait_time (0, 10);
+
+ for (;;)
+ {
+ if (this->acceptor_.accept (stream) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("HTTP_Acceptor::accept")), -1);
+
+ Thread_Per_Request_Task *t;
+ // Pass grp_id as a constructor param instead of into open.
+ ACE_NEW_RETURN (t, Thread_Per_Request_Task (stream.get_handle (),
+ this->tm_,
+ grp_id,
+ factory),
+ -1);
+
+
+ if (t->open () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Thread_Per_Request_Task::open")),
+ -1);
+
+ // Throttling is not allowing too many threads to run away.
+ // Should really use some sort of condition variable here.
+ if (!this->throttle_)
+ continue;
+
+ // This works because each task has only one thread.
+ while (this->tm_.num_tasks_in_group (grp_id) > this->threads_)
+ this->tm_.wait (&wait_time);
+ }
+
+ ACE_NOTREACHED(return 0);
+}
+
+Thread_Per_Request_Task::Thread_Per_Request_Task (ACE_HANDLE handle,
+ ACE_Thread_Manager &tm,
+ int &grp_id,
+ HTTP_Handler_Factory &factory)
+ : ACE_Task<ACE_NULL_SYNCH> (&tm),
+ handle_ (handle),
+ grp_id_ (grp_id),
+ factory_ (factory)
+{
+}
+
+
+// HEY! Add a method to the thread_manager to return total number of
+// threads managed in all the tasks.
+
+int
+Thread_Per_Request_Task::open (void *)
+{
+ int status = -1;
+
+ if (this->grp_id_ == -1)
+ status = this->grp_id_ = this->activate (THR_DETACHED | THR_NEW_LWP);
+ else
+ status = this->activate (THR_DETACHED | THR_NEW_LWP,
+ 1, 0, -1, this->grp_id_, 0);
+
+ if (status == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Thread_Per_Request_Task::open")),
+ -1);
+ return 0;
+}
+
+int
+Thread_Per_Request_Task::svc (void)
+{
+ ACE_Message_Block *mb;
+ ACE_NEW_RETURN (mb, ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1),
+ -1);
+ //Synch_HTTP_Handler_Factory factory;
+ HTTP_Handler *handler = this->factory_.create_http_handler ();
+ handler->open (this->handle_, *mb);
+ mb->release ();
+ return 0;
+}
+
+int
+Thread_Per_Request_Task::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) Thread_Per_Request_Task::svc, dying\n")));
+ delete this;
+ return 0;
+}
+
+// Understanding the code below requires understanding of the
+// WindowsNT asynchronous completion notification mechanism and the
+// Proactor Pattern.
+
+// (1) The application submits an asynchronous I/O request to the
+// operating system and a special handle with it (Asynchronous
+// Completion Token).
+// (2) The operating system commits to performing the I/O request,
+// while application does its own thing.
+// (3) Operating system finishes the I/O request and places ACT onto
+// the I/O Completion Port, which is a queue of finished
+// asynchronous requests.
+// (4) The application eventually checks to see if the I/O request
+// is done by checking the I/O Completion Port, and retrieves the
+// ACT.
+
+int
+HTTP_Server::asynch_thread_pool (void)
+{
+// This only works on Win32
+#if defined (ACE_WIN32)
+ // Create the appropriate acceptor for this concurrency strategy and
+ // an appropriate handler for this I/O strategy
+ ACE_Asynch_Acceptor<Asynch_HTTP_Handler_Factory> acceptor;
+
+ // Tell the acceptor to listen on this->port_, which makes an
+ // asynchronous I/O request to the OS.
+ if (acceptor.open (ACE_INET_Addr (this->port_),
+ HTTP_Handler::MAX_REQUEST_SIZE + 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_Asynch_Acceptor::open")), -1);
+
+ // Create the thread pool.
+ // Register threads with the proactor and thread manager.
+ Asynch_Thread_Pool_Task t (*ACE_Proactor::instance (),
+ this->tm_);
+
+ // The proactor threads are waiting on the I/O Completion Port.
+
+ // Wait for the threads to finish.
+ return this->tm_.wait ();
+#endif /* ACE_WIN32 */
+ return -1;
+}
+
+// This only works on Win32
+#if defined (ACE_WIN32)
+
+Asynch_Thread_Pool_Task::Asynch_Thread_Pool_Task (ACE_Proactor &proactor,
+ ACE_Thread_Manager &tm)
+ : ACE_Task<ACE_NULL_SYNCH> (&tm),
+ proactor_ (proactor)
+{
+ if (this->activate () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Asynch_Thread_Pool_Task::open")));
+}
+
+int
+Asynch_Thread_Pool_Task::svc (void)
+{
+ for (;;)
+ if (this->proactor_.handle_events () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_Proactor::handle_events")),
+ -1);
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 */
+
+// Define the factory function.
+ACE_SVC_FACTORY_DEFINE (HTTP_Server)
+
+// Define the object that describes the service.
+ACE_STATIC_SVC_DEFINE (HTTP_Server, ACE_TEXT ("HTTP_Server"), ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (HTTP_Server),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ, 0)
+
diff --git a/ACE/apps/JAWS/server/HTTP_Server.h b/ACE/apps/JAWS/server/HTTP_Server.h
new file mode 100644
index 00000000000..9e8534c4cbd
--- /dev/null
+++ b/ACE/apps/JAWS/server/HTTP_Server.h
@@ -0,0 +1,155 @@
+// -*- C++ -*-
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// HTTP_Server.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef HTTP_SERVER_H
+#define HTTP_SERVER_H
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Service_Config.h"
+#include "ace/Service_Object.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Acceptor.h"
+#include "ace/LOCK_SOCK_Acceptor.h"
+#include "ace/Task_T.h"
+#include "ace/Asynch_IO.h"
+#include "ace/svc_export.h"
+#include "HTTP_Handler.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Global_Macros.h"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+// Forward declaration.
+class ACE_Proactor;
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+#if defined (ACE_HAS_THREAD_SAFE_ACCEPT)
+typedef ACE_LOCK_SOCK_Acceptor<ACE_SYNCH_NULL_MUTEX> HTTP_SOCK_Acceptor;
+#else
+typedef ACE_LOCK_SOCK_Acceptor<ACE_SYNCH_MUTEX> HTTP_SOCK_Acceptor;
+#endif /* ACE_HAS_THREAD_SAFE_ACCEPT */
+
+typedef HTTP_SOCK_Acceptor HTTP_Acceptor;
+
+class ACE_Svc_Export HTTP_Server : public ACE_Service_Object
+ // = TITLE
+ // This server is used to create HTTP Handlers for the Web
+ // server
+ //
+ // = DESCRIPTION
+{
+public:
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ // Initialization
+
+ virtual int fini (void);
+ // Exit hooks
+
+protected:
+ virtual int thread_per_request (HTTP_Handler_Factory &factory);
+ // Thread Per Request implementation
+
+ virtual int asynch_thread_pool (void);
+ // Asynch Thread Pool implementation
+
+ virtual int synch_thread_pool (HTTP_Handler_Factory &factory);
+ // Synch Thread Pool implementation
+
+private:
+ // James, comment these data members.
+ void parse_args (int argc, ACE_TCHAR **argv);
+ int port_;
+ int threads_;
+ int strategy_;
+ int backlog_;
+ int throttle_;
+ bool caching_;
+ ACE_Thread_Manager tm_;
+ HTTP_Acceptor acceptor_;
+};
+
+class Synch_Thread_Pool_Task : public ACE_Task<ACE_NULL_SYNCH>
+ // = TITLE
+ // Used to implement Synch Thread Pool
+ //
+ // = DESCRIPTION
+ // Describe this and the others below.
+ // NOTE: this class was modified to make caching disabling possible
+{
+public:
+ Synch_Thread_Pool_Task (HTTP_Acceptor &acceptor,
+ ACE_Thread_Manager &tm,
+ int threads,
+ HTTP_Handler_Factory &factory);
+ virtual int svc (void);
+
+private:
+ HTTP_Acceptor &acceptor_;
+ HTTP_Handler_Factory &factory_;
+};
+
+class Thread_Per_Request_Task : public ACE_Task<ACE_NULL_SYNCH>
+ // = TITLE
+ // Used to implement Thread Per Request.
+ //
+ // = DESCRIPTION
+ // Spawns a new thread for every new incoming connection. The
+ // handle below is the socket stream of the incoming connection.
+ // NOTE: this class was modified to make caching disabling possible
+{
+public:
+ Thread_Per_Request_Task (ACE_HANDLE handle,
+ ACE_Thread_Manager &tm,
+ int &grp_id,
+ HTTP_Handler_Factory &factory);
+ virtual int open (void *args = 0);
+ virtual int close (u_long);
+ virtual int svc (void);
+
+private:
+ ACE_HANDLE handle_;
+ int &grp_id_;
+ HTTP_Handler_Factory &factory_;
+};
+
+// This only works on Win32
+#if defined (ACE_WIN32)
+class Asynch_Thread_Pool_Task : public ACE_Task<ACE_NULL_SYNCH>
+ // = TITLE
+ // Used to implement Asynch Thread Pool
+ //
+ // = DESCRIPTION
+ // The proactor below utilizes WaitForMultipleObjects.
+{
+public:
+ Asynch_Thread_Pool_Task (ACE_Proactor &proactor,
+ ACE_Thread_Manager &tm);
+ virtual int svc (void);
+
+private:
+ ACE_Proactor &proactor_;
+};
+#endif /* ACE_WIN32 */
+
+ACE_SVC_FACTORY_DECLARE (HTTP_Server)
+
+ACE_STATIC_SVC_DECLARE_EXPORT (ACE_Svc, HTTP_Server)
+
+#endif /* HTTP_SERVER_H */
diff --git a/ACE/apps/JAWS/server/IO.cpp b/ACE/apps/JAWS/server/IO.cpp
new file mode 100644
index 00000000000..e08b7d89f64
--- /dev/null
+++ b/ACE/apps/JAWS/server/IO.cpp
@@ -0,0 +1,570 @@
+// $Id$
+
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_uio.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/Message_Block.h"
+#include "ace/Min_Max.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Filecache.h"
+#include "IO.h"
+#include "HTTP_Helpers.h"
+
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/Auto_Ptr.h"
+
+ACE_RCSID (server,
+ IO,
+ "$Id$")
+
+
+JAWS_IO::JAWS_IO (void)
+ : handler_ (0)
+{
+}
+
+JAWS_IO::~JAWS_IO (void)
+{
+}
+
+void
+JAWS_IO::handler (JAWS_IO_Handler *handler)
+{
+ this->handler_ = handler;
+}
+
+JAWS_IO_Handler::~JAWS_IO_Handler (void)
+{
+}
+
+JAWS_Synch_IO::JAWS_Synch_IO (void)
+ : handle_ (ACE_INVALID_HANDLE)
+{
+}
+
+JAWS_Synch_IO::~JAWS_Synch_IO (void)
+{
+ ACE_OS::closesocket (this->handle_);
+}
+
+ACE_HANDLE
+JAWS_Synch_IO::handle (void) const
+{
+ return this->handle_;
+}
+
+void
+JAWS_Synch_IO::handle (ACE_HANDLE handle)
+{
+ this->handle_ = handle;
+}
+
+void
+JAWS_Synch_IO::read (ACE_Message_Block &mb,
+ int size)
+{
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+ int result = stream.recv (mb.wr_ptr (), size);
+
+ if (result <= 0)
+ this->handler_->read_error ();
+ else
+ {
+ mb.wr_ptr (result);
+ this->handler_->read_complete (mb);
+ }
+}
+
+void
+JAWS_Synch_IO::receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length)
+{
+ ACE_Filecache_Handle handle (filename, entire_length);
+
+ int result = handle.error ();
+
+ if (result == ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+
+ int bytes_to_memcpy = ACE_MIN (entire_length, initial_data_length);
+ ACE_OS::memcpy (handle.address (), initial_data, bytes_to_memcpy);
+
+ int bytes_to_read = entire_length - bytes_to_memcpy;
+
+ int bytes = stream.recv_n ((char *) handle.address () + initial_data_length,
+ bytes_to_read);
+ if (bytes == bytes_to_read)
+ this->handler_->receive_file_complete ();
+ else
+ result = -1;
+ }
+
+ if (result != ACE_Filecache_Handle::ACE_SUCCESS)
+ this->handler_->receive_file_error (result);
+}
+
+void
+JAWS_Synch_IO::transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size)
+{
+ ACE_Filecache_Handle handle (filename);
+
+ int result = handle.error ();
+
+ if (result == ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+#if defined (ACE_JAWS_BASELINE) || defined (ACE_WIN32)
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+
+ if ((stream.send_n (header, header_size) == header_size)
+ && (stream.send_n (handle.address (), handle.size ())
+ == handle.size ())
+ && (stream.send_n (trailer, trailer_size) == trailer_size))
+ this->handler_->transmit_file_complete ();
+ else
+ result = -1;
+#else
+ // Attempting to use writev
+ // Is this faster?
+ iovec iov[3];
+ int iovcnt = 0;
+ if (header_size > 0)
+ {
+ iov[iovcnt].iov_base = const_cast<char*> (header);
+ iov[iovcnt].iov_len = header_size;
+ iovcnt++;
+ }
+ if (handle.size () > 0)
+ {
+ iov[iovcnt].iov_base = reinterpret_cast<char*> (handle.address ());
+ iov[iovcnt].iov_len = handle.size ();
+ iovcnt++;
+ }
+ if (trailer_size > 0)
+ {
+ iov[iovcnt].iov_base = const_cast<char*> (trailer);
+ iov[iovcnt].iov_len = trailer_size;
+ iovcnt++;
+ }
+ if (ACE_OS::writev (this->handle_, iov, iovcnt) < 0)
+ result = -1;
+ else
+ this->handler_->transmit_file_complete ();
+#endif /* ACE_JAWS_BASELINE */
+ }
+
+ if (result != ACE_Filecache_Handle::ACE_SUCCESS)
+ this->handler_->transmit_file_error (result);
+}
+
+void
+JAWS_Synch_IO::send_confirmation_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length);
+ this->handler_->confirmation_message_complete ();
+}
+
+void
+JAWS_Synch_IO::send_error_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length);
+ this->handler_->error_message_complete ();
+}
+
+void
+JAWS_Synch_IO::send_message (const char *buffer,
+ int length)
+{
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+ stream.send_n (buffer, length);
+}
+
+// This only works on Win32
+#if defined (ACE_WIN32)
+
+JAWS_Asynch_IO::JAWS_Asynch_IO (void)
+{
+}
+
+JAWS_Asynch_IO::~JAWS_Asynch_IO (void)
+{
+ ACE_OS::closesocket (this->handle_);
+}
+
+void
+JAWS_Asynch_IO::read (ACE_Message_Block& mb,
+ int size)
+{
+ ACE_Asynch_Read_Stream ar;
+
+ if (ar.open (*this, this->handle_) == -1
+ || ar.read (mb, size) == -1)
+ this->handler_->read_error ();
+}
+
+// This method will be called when an asynchronous read completes on a
+// stream.
+
+void
+JAWS_Asynch_IO::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ // This callback is for this->receive_file()
+ if (result.act () != 0)
+ {
+ int code = 0;
+ if (result.success () && result.bytes_transferred () != 0)
+ {
+ if (result.message_block ().length () == result.message_block ().size ())
+ code = ACE_Filecache_Handle::ACE_SUCCESS;
+ else
+ {
+ ACE_Asynch_Read_Stream ar;
+ if (ar.open (*this, this->handle_) == -1
+ || ar.read (result.message_block (),
+ result.message_block ().size () - result.message_block ().length (),
+ result.act ()) == -1)
+ code = -1;
+ else
+ return;
+ }
+ }
+ else
+ code = -1;
+
+ if (code == ACE_Filecache_Handle::ACE_SUCCESS)
+ this->handler_->receive_file_complete ();
+ else
+ this->handler_->receive_file_error (code);
+
+ delete &result.message_block ();
+ delete (ACE_Filecache_Handle *) result.act ();
+ }
+ else
+ {
+ // This callback is for this->read()
+ if (result.success ()
+ && result.bytes_transferred () != 0)
+ this->handler_->read_complete (result.message_block ());
+ else
+ this->handler_->read_error ();
+ }
+}
+
+void
+JAWS_Asynch_IO::receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length)
+{
+ ACE_Message_Block *mb = 0;
+ ACE_Filecache_Handle *handle;
+
+ ACE_NEW (handle, ACE_Filecache_Handle (filename, entire_length, ACE_NOMAP));
+
+ int result = handle->error ();
+
+ if (result == ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+ ACE_OS::memcpy (handle->address (),
+ initial_data,
+ initial_data_length);
+
+ int bytes_to_read = entire_length - initial_data_length;
+
+ ACE_NEW (mb, ACE_Message_Block ((char *)handle->address ()
+ + initial_data_length, bytes_to_read));
+
+ if (mb == 0)
+ {
+ errno = ENOMEM;
+ result = -1;
+ }
+ else
+ {
+ ACE_Asynch_Read_Stream ar;
+
+ if (ar.open (*this, this->handle_) == -1
+ || ar.read (*mb, mb->size () - mb->length (), handle) == -1)
+ result = -1;
+ }
+ }
+
+ if (result != ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+ this->handler_->receive_file_error (result);
+ delete mb;
+ delete handle;
+ }
+}
+
+void
+JAWS_Asynch_IO::transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size)
+{
+ ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer = 0;
+ ACE_Filecache_Handle *handle = new ACE_Filecache_Handle (filename, ACE_NOMAP);
+
+ int result = handle->error ();
+
+ if (result == ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+ ACE_Message_Block header_mb (header, header_size);
+ ACE_Message_Block trailer_mb (trailer, trailer_size);
+
+ header_and_trailer = new ACE_Asynch_Transmit_File::Header_And_Trailer
+ (&header_mb, header_size, &trailer_mb, trailer_size);
+
+ ACE_Asynch_Transmit_File tf;
+
+ if (tf.open (*this, this->handle_) == -1
+ || tf.transmit_file (handle->handle (), // file handle
+ header_and_trailer, // header and trailer data
+ 0, // bytes_to_write
+ 0, // offset
+ 0, // offset_high
+ 0, // bytes_per_send
+ 0, // flags
+ handle // act
+ ) == -1)
+ result = -1;
+ }
+
+ if (result != ACE_Filecache_Handle::ACE_SUCCESS)
+ {
+ this->handler_->transmit_file_error (result);
+ delete header_and_trailer;
+ delete handle;
+ }
+}
+
+
+// This method will be called when an asynchronous transmit file completes.
+void
+JAWS_Asynch_IO::handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result)
+{
+ if (result.success ())
+ this->handler_->transmit_file_complete ();
+ else
+ this->handler_->transmit_file_error (-1);
+
+ delete result.header_and_trailer ();
+ delete (ACE_Filecache_Handle *) result.act ();
+}
+
+void
+JAWS_Asynch_IO::send_confirmation_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length, CONFORMATION);
+}
+
+void
+JAWS_Asynch_IO::send_error_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length, ERROR_MESSAGE);
+}
+
+void
+JAWS_Asynch_IO::send_message (const char *buffer,
+ int length,
+ int act)
+{
+ ACE_Message_Block *mb;
+ ACE_NEW (mb, ACE_Message_Block (buffer, length));
+
+ if (mb == 0)
+ {
+ this->handler_->error_message_complete ();
+ return;
+ }
+
+ ACE_Asynch_Write_Stream aw;
+ if (aw.open (*this, this->handle_) == -1
+ || aw.write (*mb, length, (void *) act) == -1)
+ {
+ mb->release ();
+
+ if (act == CONFORMATION)
+ this->handler_->confirmation_message_complete ();
+ else
+ this->handler_->error_message_complete ();
+ }
+}
+
+void
+JAWS_Asynch_IO::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ result.message_block ().release ();
+
+ if (result.act () == (void *) CONFORMATION)
+ this->handler_->confirmation_message_complete ();
+ else
+ this->handler_->error_message_complete ();
+}
+
+#endif /* ACE_WIN32 */
+
+//-------------------Adding SYNCH IO no Caching
+
+JAWS_Synch_IO_No_Cache::JAWS_Synch_IO_No_Cache (void)
+ : handle_ (ACE_INVALID_HANDLE)
+{
+}
+
+JAWS_Synch_IO_No_Cache::~JAWS_Synch_IO_No_Cache (void)
+{
+ ACE_OS::closesocket (this->handle_);
+}
+
+ACE_HANDLE
+JAWS_Synch_IO_No_Cache::handle (void) const
+{
+ return this->handle_;
+}
+
+void
+JAWS_Synch_IO_No_Cache::handle (ACE_HANDLE handle)
+{
+ this->handle_ = handle;
+}
+
+void
+JAWS_Synch_IO_No_Cache::read (ACE_Message_Block &mb,
+ int size)
+{
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+ int result = stream.recv (mb.wr_ptr (), size);
+
+ if (result <= 0)
+ this->handler_->read_error ();
+ else
+ {
+ mb.wr_ptr (result);
+ this->handler_->read_complete (mb);
+ }
+}
+
+void
+JAWS_Synch_IO_No_Cache::receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length)
+{
+ //ugly hack to send HTTP_Status_Code::STATUS_FORBIDDEN
+ this->handler_->receive_file_error (5);
+
+ //To get rid of warnings on some platforms
+ //NOTE: this function is necessary because the base class
+ //version of the function is pure virtual
+ ACE_UNUSED_ARG (filename);
+ ACE_UNUSED_ARG (initial_data);
+ ACE_UNUSED_ARG (initial_data_length);
+ ACE_UNUSED_ARG (entire_length);
+}
+
+void
+JAWS_Synch_IO_No_Cache::transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size)
+{
+ int result = 0;
+
+ // Can we access the file?
+ if (ACE_OS::access (filename, R_OK) == -1)
+ {
+ //ugly hack to send in HTTP_Status_Code::STATUS_NOT_FOUND
+ result = ACE_Filecache_Handle::ACE_ACCESS_FAILED;
+ this->handler_->transmit_file_error (result);
+ return;
+ }
+
+ ACE_stat stat;
+
+ // Can we stat the file?
+ if (ACE_OS::stat (filename, &stat) == -1)
+ {
+ //ugly hack to send HTTP_Status_Code::STATUS_FORBIDDEN
+ result = ACE_Filecache_Handle::ACE_STAT_FAILED;
+ this->handler_->transmit_file_error (result);
+ return;
+ }
+
+ ssize_t size = stat.st_size;
+
+ // Can we open the file?
+ ACE_HANDLE handle = ACE_OS::open (filename, O_RDONLY);
+ if (handle == ACE_INVALID_HANDLE)
+ {
+ //ugly hack to send HTTP_Status_Code::STATUS_FORBIDDEN
+ result = ACE_Filecache_Handle::ACE_OPEN_FAILED;
+ this->handler_->transmit_file_error (result);
+ return;
+ }
+
+ char* f = new char[size];
+ auto_ptr<char> file (f);
+
+ ACE_OS::read_n (handle, f, size);
+
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+
+ if ((stream.send_n (header, header_size) == header_size)
+ && (stream.send_n (f, size) == size)
+ && (stream.send_n (trailer, trailer_size) == trailer_size))
+ this->handler_->transmit_file_complete ();
+ else
+ {
+ //ugly hack to default to HTTP_Status_Code::STATUS_INTERNAL_SERVER_ERROR
+ result = -1;
+ this->handler_->transmit_file_error (result);
+ return;
+ }
+}
+
+void
+JAWS_Synch_IO_No_Cache::send_confirmation_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length);
+ this->handler_->confirmation_message_complete ();
+}
+
+void
+JAWS_Synch_IO_No_Cache::send_error_message (const char *buffer,
+ int length)
+{
+ this->send_message (buffer, length);
+ this->handler_->error_message_complete ();
+}
+
+void
+JAWS_Synch_IO_No_Cache::send_message (const char *buffer,
+ int length)
+{
+ ACE_SOCK_Stream stream;
+ stream.set_handle (this->handle_);
+ stream.send_n (buffer, length);
+}
+
diff --git a/ACE/apps/JAWS/server/IO.h b/ACE/apps/JAWS/server/IO.h
new file mode 100644
index 00000000000..fd5ae0d64b2
--- /dev/null
+++ b/ACE/apps/JAWS/server/IO.h
@@ -0,0 +1,296 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// IO.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef JAWS_IO_H
+#define JAWS_IO_H
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Asynch_IO.h"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+class ACE_Message_Block;
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+class JAWS_IO_Handler;
+
+
+class JAWS_IO
+ // = TITLE
+ //
+ // This class defines the abstract interface for an I/O class in
+ // the context of Web-likes servers
+ //
+ // = DESCRIPTION
+ //
+ // An I/O class should have the following interface. Derived
+ // classes will define the exactly how the I/O will take place
+ // (Asynchronous, Synchronous, Reactive)
+{
+public:
+ JAWS_IO (void);
+ virtual ~JAWS_IO (void);
+ void handler (JAWS_IO_Handler *handler);
+
+ virtual void handle (ACE_HANDLE h) = 0;
+ virtual ACE_HANDLE handle (void) const = 0;
+
+ // James, please add documentation here.
+
+ virtual void read (ACE_Message_Block& mb, int size) = 0;
+ // read from the handle size bytes into the message block.
+
+ virtual void transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size) = 0;
+ // send header, filename, trailer to the handle.
+
+ virtual void receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length) = 0;
+ // read data from the handle and store in filename.
+
+ virtual void send_confirmation_message (const char *buffer, int length) = 0;
+ // send a confirmation message to the handle.
+
+ virtual void send_error_message (const char *buffer, int length) = 0;
+ // send an error message to the handle.
+
+protected:
+ JAWS_IO_Handler *handler_;
+};
+
+class JAWS_IO_Handler
+ // = TITLE
+ //
+ // This class defines the abstract interface for an I/O handler class in
+ // the context of Web-likes servers
+ //
+ // = DESCRIPTION
+{
+public:
+
+ /// Destructor.
+ virtual ~JAWS_IO_Handler (void);
+
+ virtual void read_complete (ACE_Message_Block &data) = 0;
+ // This method is called by the IO class when new client data shows
+ // up.
+
+ virtual void read_error (void) = 0;
+ // This method is called by the IO class when there was an error in
+ // reading new data from the client.
+
+ virtual void transmit_file_complete (void) = 0;
+ // This method is called by the IO class when the requested file has
+ // been successfully transmitted to the client.
+
+ virtual void transmit_file_error (int result) = 0;
+ // This method is called by the IO class when there was an error in
+ // transmitting the requested file to the client.
+
+ virtual void receive_file_complete (void) = 0;
+ // This method is called by the IO class when the requested file has
+ // been successfully received from the client.
+
+ virtual void receive_file_error (int result) = 0;
+ // This method is called by the IO class when there was an error in
+ // receiving the requested file from the client.
+
+ virtual void write_error (void) = 0;
+ // This method is called by the IO class when there was an error in
+ // writing data to the client.
+
+ virtual void confirmation_message_complete (void) = 0;
+ // This method is called by the IO class when the confirmation
+ // message has been delivered to the client.
+
+ virtual void error_message_complete (void) = 0;
+ // This method is called by the IO class when the error message has
+ // been delivered to the client.
+
+};
+
+class JAWS_Synch_IO : public JAWS_IO
+ // = TITLE
+ //
+ // This class defines the interface for a Synchronous I/O class.
+ //
+ // = DESCRIPTION
+{
+public:
+ JAWS_Synch_IO (void);
+
+ ~JAWS_Synch_IO (void);
+
+ virtual void handle (ACE_HANDLE h);
+ virtual ACE_HANDLE handle (void) const;
+
+ void read (ACE_Message_Block& mb, int size);
+
+ void transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size);
+
+ void receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length);
+
+ void send_confirmation_message (const char *buffer,
+ int length);
+
+ void send_error_message (const char *buffer,
+ int length);
+
+protected:
+ virtual void send_message (const char *buffer,
+ int length);
+
+ ACE_HANDLE handle_;
+};
+
+// This only works on Win32
+#if defined (ACE_WIN32)
+
+class JAWS_Asynch_IO : public JAWS_IO, public ACE_Handler
+ // = TITLE
+ //
+ // This class defines the interface for a Asynchronous I/O class.
+ //
+ // = DESCRIPTION
+{
+public:
+ JAWS_Asynch_IO (void);
+
+ ~JAWS_Asynch_IO (void);
+
+ virtual void handle (ACE_HANDLE h) { ACE_Handler::handle (h); };
+ virtual ACE_HANDLE handle (void) const { return ACE_Handler::handle (); };
+
+ void read (ACE_Message_Block& mb, int size);
+
+ void transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size);
+
+ void receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length);
+
+ void send_confirmation_message (const char *buffer,
+ int length);
+
+ void send_error_message (const char *buffer,
+ int length);
+
+protected:
+ enum Message_Types
+ {
+ CONFORMATION,
+ ERROR_MESSAGE
+ };
+
+ virtual void send_message (const char *buffer,
+ int length,
+ int act);
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This method will be called when an asynchronous read completes on
+ // a stream.
+
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This method will be called when an asynchronous write completes
+ // on a stream.
+
+ virtual void handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result);
+ // This method will be called when an asynchronous transmit file
+ // completes.
+};
+
+#endif /* ACE_WIN32 */
+
+
+//-------------------Adding SYNCH IO no Caching
+
+class JAWS_Synch_IO_No_Cache : public JAWS_IO
+ // = TITLE
+ //
+ // This class defines the interface for a Synchronous I/O class,
+ // however in this class we do not use any caching.
+ //
+ // = DESCRIPTION
+ //
+ // Wondering how this is useful?
+ // The ACE_Filecache ACE_NOMAP option is broken and even if it were not, there
+ // are other use cases in which we want to avoid caching altogether. For example,
+ // we use JAWS in conjunction with the CIAO Repository Manager, however the two
+ // do not have any explicit knowledge of each other. Therefore if the RM tried
+ // to remove a package and its files from disk, its operation would [partially]
+ // fail if JAWS still holds some of the files in its cache.
+ //
+{
+public:
+ JAWS_Synch_IO_No_Cache (void);
+
+ ~JAWS_Synch_IO_No_Cache (void);
+
+ virtual void handle (ACE_HANDLE h);
+ virtual ACE_HANDLE handle (void) const;
+
+ void read (ACE_Message_Block& mb, int size);
+
+ void transmit_file (const char *filename,
+ const char *header,
+ int header_size,
+ const char *trailer,
+ int trailer_size);
+
+ void receive_file (const char *filename,
+ void *initial_data,
+ int initial_data_length,
+ int entire_length);
+
+ void send_confirmation_message (const char *buffer,
+ int length);
+
+ void send_error_message (const char *buffer,
+ int length);
+
+protected:
+ virtual void send_message (const char *buffer,
+ int length);
+
+ ACE_HANDLE handle_;
+};
+
+//-------------------
+
+#endif /* JAWS_IO_H */
+
diff --git a/ACE/apps/JAWS/server/JAWS_Concurrency.cpp b/ACE/apps/JAWS/server/JAWS_Concurrency.cpp
new file mode 100644
index 00000000000..4d7388d6f8a
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Concurrency.cpp
@@ -0,0 +1,82 @@
+// $Id$
+
+#include "JAWS_Concurrency.h"
+
+ACE_RCSID(server, JAWS_Concurrency, "$Id$")
+
+JAWS_Concurrency_Base::JAWS_Concurrency_Base (void)
+{
+}
+
+int
+JAWS_Concurrency_Base::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ return this->putq (mb, tv);
+}
+
+int
+JAWS_Concurrency_Base::svc (void)
+{
+ int result = 0;
+
+ for (;;)
+ {
+ ACE_Message_Block *mb;
+
+ // At this point we could set a timeout value so that the
+ // threading strategy can delete a thread if there is nothing to
+ // do. Carefully think how to implement it so you don't leave
+ // yourself with 0 threads.
+
+ result = this->getq (mb);
+ if (result == -1 || mb == 0)
+ break;
+
+ this->put_next (mb);
+ }
+ return 0;
+}
+
+JAWS_Dispatch_Policy::JAWS_Dispatch_Policy (void)
+{
+}
+
+JAWS_Dispatch_Policy::~JAWS_Dispatch_Policy (void)
+{
+}
+
+JAWS_Dispatcher::JAWS_Dispatcher (JAWS_Dispatch_Policy *policy)
+ : policy_(policy)
+{
+}
+
+JAWS_Thread_Pool_Task::JAWS_Thread_Pool_Task (long flags,
+ int nthreads,
+ int maxthreads)
+ : nthreads_ (nthreads),
+ maxthreads_ (maxthreads)
+{
+ if (this->activate (flags, nthreads) == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "JAWS_Thread_Pool_Task::activate"));
+}
+
+JAWS_Thread_Per_Task::JAWS_Thread_Per_Task (long flags, int maxthreads)
+ : flags_ (flags),
+ maxthreads_ (maxthreads)
+{
+}
+
+int
+JAWS_Thread_Per_Task::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ const int force_active = 1;
+ const int nthreads = 1;
+
+ if (this->activate (this->flags_, nthreads, force_active) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "JAWS_Thread_Pool_Task::activate"),
+ -1);
+
+ this->putq (mb, tv);
+
+ return 0;
+}
diff --git a/ACE/apps/JAWS/server/JAWS_Concurrency.h b/ACE/apps/JAWS/server/JAWS_Concurrency.h
new file mode 100644
index 00000000000..7096d1dbefa
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Concurrency.h
@@ -0,0 +1,101 @@
+/* -*- c++ -*- */
+// $Id$
+
+#ifndef JAWS_CONCURRENCY_H
+#define JAWS_CONCURRENCY_H
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task.h"
+#include "IO.h"
+
+class JAWS_Concurrency_Base : public ACE_Task<ACE_SYNCH>
+ // = TITLE
+ // Base class for different concurrency models
+ //
+ // = DESCRIPTION
+ // Provides a default implementaion of the virtual put() method
+ // which calls putq(), but can be overloaded to do something
+ // synchronously, such as call put_next().
+
+{
+public:
+ JAWS_Concurrency_Base (void);
+ virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv = 0);
+ virtual int svc (void);
+};
+
+class JAWS_Dispatch_Policy
+ // = TITLE
+ // Policy mechanism for choosing different concurrency models.
+ //
+ // = DESCRIPTION
+ // Given some (unspecified) state, decides what the concurrency
+ // model should be. (For now, we always return the same model.)
+{
+public:
+ JAWS_Dispatch_Policy (void);
+ virtual ~JAWS_Dispatch_Policy (void);
+ virtual JAWS_Concurrency_Base * update (void *state = 0) = 0;
+};
+
+class JAWS_Dispatcher
+ // = TITLE
+ // The class that is responsible to delivering events to the
+ // appropriate concurrency mechanism.
+ //
+ // = DESCRIPTION
+ // JAWS_IO_Handler calls into the dispatcher so that the completed
+ // IO can find a thread to take care of it.
+{
+public:
+ JAWS_Dispatcher (JAWS_Dispatch_Policy *policy);
+
+ int dispatch (JAWS_IO_Handler *ioh);
+
+private:
+ JAWS_Dispatch_Policy *policy_;
+};
+
+class JAWS_Thread_Pool_Task : public JAWS_Concurrency_Base
+ // = TITLE
+ // Used to implement Thread Pool Concurrency Strategy
+ //
+ // = DESCRIPTION
+ // This task is created to hold a pool of threads that receive
+ // requests through the message queue.
+{
+public:
+ JAWS_Thread_Pool_Task (long flags = THR_NEW_LWP,
+ int nthreads = 5,
+ int maxthreads = 20);
+
+private:
+ int nthreads_;
+ int maxthreads_;
+};
+
+class JAWS_Thread_Per_Task : public JAWS_Concurrency_Base
+ // = TITLE
+ // Used to implement Thread Per Request Concurrency Strategy
+ //
+ // = DESCRIPTION
+ // As each new message arrives from the queue, a new thread is
+ // spawned to handle it. This is done by overloading put to call
+ // activate.
+{
+public:
+ JAWS_Thread_Per_Task (long flags = THR_NEW_LWP, int maxthreads = 20);
+
+ virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv = 0);
+
+private:
+ long flags_;
+ int maxthreads_;
+};
+
+#endif /* !defined (JAWS_CONCURRENCY_H) */
diff --git a/ACE/apps/JAWS/server/JAWS_Pipeline.cpp b/ACE/apps/JAWS/server/JAWS_Pipeline.cpp
new file mode 100644
index 00000000000..f2ea3ecfbe9
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Pipeline.cpp
@@ -0,0 +1,29 @@
+// $Id$
+
+#include "JAWS_Pipeline.h"
+
+ACE_RCSID(server, JAWS_Pipeline, "$Id$")
+
+JAWS_Pipeline::JAWS_Pipeline (void)
+{
+}
+
+int
+JAWS_Pipeline::open (void *)
+{
+ // Simply call into the virtual svc() method.
+ if (this->svc () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "JAWS_Pipeline::svc"),
+ -1);
+ return 0;
+}
+
+int
+JAWS_Pipeline::close (u_long)
+{
+ return 0;
+}
+
+#include "JAWS_Pipeline_Handler.cpp"
diff --git a/ACE/apps/JAWS/server/JAWS_Pipeline.h b/ACE/apps/JAWS/server/JAWS_Pipeline.h
new file mode 100644
index 00000000000..919c982977c
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Pipeline.h
@@ -0,0 +1,36 @@
+/* -*- c++ -*- */
+// $Id$
+
+#ifndef JAWS_PIPELINE_H
+#define JAWS_PIPELINE_H
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Service_Config.h"
+#include "ace/Stream.h"
+#include "ace/Module.h"
+#include "ace/Task.h"
+
+typedef ACE_Stream<ACE_NULL_SYNCH> JAWS_Pipeline_Stream;
+typedef ACE_Module<ACE_NULL_SYNCH> JAWS_Pipeline_Module;
+typedef ACE_Task<ACE_NULL_SYNCH> JAWS_Pipeline_Task;
+
+class JAWS_Pipeline : public JAWS_Pipeline_Task
+ // = TITLE
+ // Methods that are common to pipeline components
+{
+public:
+ JAWS_Pipeline (void);
+ // ACE_Task hooks
+
+ virtual int open (void * = 0);
+ virtual int close (u_long = 0);
+};
+
+#include "JAWS_Pipeline_Handler.h"
+
+#endif /* !defined (JAWS_PIPELINE_H) */
diff --git a/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.cpp b/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.cpp
new file mode 100644
index 00000000000..e67a99545bb
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.cpp
@@ -0,0 +1,25 @@
+// $Id$
+
+#ifndef JAWS_PIPELINE_HANDLER_CPP
+#define JAWS_PIPELINE_HANDLER_CPP
+
+#include "JAWS_Pipeline_Handler.h"
+
+ACE_RCSID(server, JAWS_Pipeline_Handler, "$Id$")
+
+template <class TYPE>
+JAWS_Pipeline_Handler<TYPE>::JAWS_Pipeline_Handler (void)
+{
+}
+
+template <class TYPE> int
+JAWS_Pipeline_Handler<TYPE>::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ TYPE *data = dynamic_cast<TYPE *> (mb->data_block ());
+
+ int status = this->handle_input (data, tv);
+
+ return (status != -1) ? this->put_next (mb, tv) : -1;
+}
+
+#endif /* !defined (JAWS_PIPELINE_HANDLER_CPP) */
diff --git a/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.h b/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.h
new file mode 100644
index 00000000000..7e9becb6f5e
--- /dev/null
+++ b/ACE/apps/JAWS/server/JAWS_Pipeline_Handler.h
@@ -0,0 +1,29 @@
+/* -*- c++ -*- */
+// $Id$
+
+#ifndef JAWS_PIPELINE_HANDLER_H
+#define JAWS_PIPELINE_HANDLER_H
+
+#include "JAWS_Pipeline.h"
+
+template <class TYPE>
+class JAWS_Pipeline_Handler : public JAWS_Pipeline_Task
+ // = TITLE
+ // Methods that are common to pipeline components
+{
+public:
+ JAWS_Pipeline_Handler (void);
+ // ACE_Task hooks
+
+ virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv = 0);
+ // inherited from ACE_Task
+
+ virtual int handle_put (TYPE *data, ACE_Time_Value *tv) = 0;
+ // Callback hook for specialized data processing
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "JAWS_Pipeline_Handler.cpp"
+#endif
+
+#endif /* !defined (JAWS_PIPELINE_HANDLER_H) */
diff --git a/ACE/apps/JAWS/server/Makefile.am b/ACE/apps/JAWS/server/Makefile.am
new file mode 100644
index 00000000000..d13d91ad381
--- /dev/null
+++ b/ACE/apps/JAWS/server/Makefile.am
@@ -0,0 +1,95 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+
+## Makefile.JAWS.am
+
+if BUILD_ACE_FILECACHE
+if !BUILD_ACE_FOR_TAO
+if !BUILD_USES_WCHAR
+
+noinst_LTLIBRARIES = libJAWS.la
+
+libJAWS_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_BUILD_SVC_DLL
+
+libJAWS_la_SOURCES = \
+ HTTP_Config.cpp \
+ HTTP_Handler.cpp \
+ HTTP_Helpers.cpp \
+ HTTP_Request.cpp \
+ HTTP_Response.cpp \
+ HTTP_Server.cpp \
+ IO.cpp \
+ JAWS_Concurrency.cpp \
+ JAWS_Pipeline.cpp \
+ Parse_Headers.cpp
+
+noinst_HEADERS = \
+ HTTP_Config.h \
+ HTTP_Handler.h \
+ HTTP_Helpers.h \
+ HTTP_Request.h \
+ HTTP_Response.h \
+ HTTP_Server.h \
+ IO.h \
+ JAWS_Concurrency.h \
+ JAWS_Pipeline.h \
+ Parse_Headers.h
+
+endif !BUILD_USES_WCHAR
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_ACE_FILECACHE
+
+## Makefile.JAWS_server.am
+
+if BUILD_ACE_FILECACHE
+if !BUILD_ACE_FOR_TAO
+if !BUILD_USES_WCHAR
+noinst_PROGRAMS = main
+
+main_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+main_SOURCES = \
+ main.cpp \
+ HTTP_Config.h \
+ HTTP_Handler.h \
+ HTTP_Helpers.h \
+ HTTP_Request.h \
+ HTTP_Response.h \
+ HTTP_Server.h \
+ IO.h \
+ JAWS_Concurrency.h \
+ JAWS_Pipeline.h \
+ JAWS_Pipeline_Handler.h \
+ Parse_Headers.h
+
+main_LDADD = \
+ libJAWS.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_USES_WCHAR
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_ACE_FILECACHE
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/apps/JAWS/server/Parse_Headers.cpp b/ACE/apps/JAWS/server/Parse_Headers.cpp
new file mode 100644
index 00000000000..0d7dd273c59
--- /dev/null
+++ b/ACE/apps/JAWS/server/Parse_Headers.cpp
@@ -0,0 +1,362 @@
+// $Id$
+
+#include "ace/Log_Msg.h"
+
+#include "Parse_Headers.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_strings.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/os_include/os_ctype.h"
+
+ACE_RCSID(server, Parse_Headers, "$Id$")
+
+// Implementation of class Headers
+
+Headers::Headers (void) : done_(0)
+{
+}
+
+Headers::~Headers (void)
+{
+}
+
+void
+Headers::recognize (const char * const header)
+{
+ (void)this->map_[header];
+}
+
+void
+Headers::parse_header_line (char * const header_line)
+{
+ char *ptr = header_line;
+ char *buf = header_line;
+ int offset = 1;
+
+ ptr = ACE_OS::strchr (header_line, '\n');
+
+ if (ptr > header_line && ptr[-1] == '\r')
+ {
+ ptr--;
+ offset++;
+ }
+
+ if (ptr == header_line)
+ {
+ this->done_ = 1;
+ return;
+ }
+
+ *ptr = '\0';
+ ptr += offset;
+
+ char *value = 0;
+ char *header = ACE_OS::strtok_r (buf, ":", &value);
+
+ ACE_DEBUG((LM_DEBUG, " (%t) Headers::parse_header_line [%s]\n",
+ header ? header : "<empty>"));
+
+ if (header != NULL && this->map_.mapped (header))
+ {
+ while (isspace (*value))
+ value++;
+
+ this->map_[header] = value;
+
+ ACE_DEBUG((LM_DEBUG, " (%t) Headers::parse_header_line <%s>\n",
+ value ? value : "<empty>"));
+ }
+
+ // Write back the unused portion of the input.
+ ACE_OS::memmove (header_line, ptr, ACE_OS::strlen(ptr) + 1);
+}
+
+int
+Headers::complete_header_line (char *const header_line)
+{
+ // Algorithm --
+ // Scan for end of line marker.
+ // If the next character is linear white space, then unfold the header.
+ // Else, if the next character is printable, we have a complete header line.
+ // Else, presumably the next character is '\0', so the header is incomplete.
+
+ // return -1 if end of line but not complete header line
+ // return 0 if no end of line marker
+ // return 1 if complete header line
+
+ char *ptr = header_line;
+ int offset;
+
+ if (!this->end_of_line (ptr, offset))
+ return 0;
+
+ if (ptr == header_line)
+ {
+ ACE_OS::memmove (ptr, ptr+offset, ACE_OS::strlen (ptr + offset) + 1);
+ this->done_ = 1;
+ ACE_DEBUG ((LM_DEBUG, " (%t) no more headers\n"));
+ return 0;
+ }
+
+ do
+ {
+ switch (ptr[offset])
+ {
+ case ' ':
+ case '\t':
+ ACE_OS::memmove (ptr, ptr+offset, ACE_OS::strlen (ptr + offset) + 1);
+ break;
+
+ case '\n':
+ case '\r':
+ return 1;
+
+ default:
+ if (isalpha (ptr[offset]))
+ return 1;
+ else
+ return -1;
+ }
+ }
+ while (this->end_of_line (ptr, offset) != 0);
+
+ return 0;
+}
+
+int
+Headers::end_of_headers (void) const
+{
+ return this->done_;
+}
+
+Headers_Map_Item &
+Headers::operator[] (const char * const header)
+{
+ return this->map_[header];
+}
+
+const Headers_Map_Item &
+Headers::operator[] (const char * const header) const
+{
+ return this->map_[header];
+}
+
+int
+Headers::end_of_line (char *&line, int &offset) const
+{
+ char *old_line = line;
+ char *ptr = ACE_OS::strchr (old_line, '\n');
+
+ if (ptr == NULL)
+ return 0;
+
+ line = ptr;
+ offset = 1;
+
+ if (line > old_line
+ && line[-1] == '\r')
+ {
+ line--;
+ offset = 2;
+ }
+
+ return 1;
+}
+
+
+// Implementation of class Headers_Map
+
+Headers_Map::Headers_Map (void)
+ : num_headers_(0)
+{
+}
+
+Headers_Map::~Headers_Map (void)
+{
+}
+
+Headers_Map_Item::Headers_Map_Item (void)
+ : header_(0),
+ value_(0)
+{
+}
+
+Headers_Map_Item::~Headers_Map_Item (void)
+{
+ ACE_OS::free ((void *) this->header_);
+ ACE_OS::free ((void *) this->value_);
+ this->header_ = this->value_ = 0;
+}
+
+// Headers_Map_Item::operator const char * (void) const
+// {
+// return this->value_ == NULL ? this->no_value_ : this->value_;
+// }
+
+Headers_Map_Item &
+Headers_Map_Item::operator= (char * value)
+{
+ ACE_OS::free ((void *) this->value_);
+ this->value_ = ACE_OS::strdup (value);
+ return *this;
+}
+
+Headers_Map_Item &
+Headers_Map_Item::operator= (const char * value)
+{
+ ACE_OS::free ((void *) this->value_);
+ this->value_ = ACE_OS::strdup (value);
+ return *this;
+}
+
+Headers_Map_Item &
+Headers_Map_Item::operator= (const Headers_Map_Item & mi)
+{
+ ACE_OS::free ((void *) this->value_);
+ ACE_OS::free ((void *) this->header_);
+ this->header_ = ACE_OS::strdup (mi.header_);
+ this->value_ = (mi.value_ ? ACE_OS::strdup (mi.value_) : 0);
+ return *this;
+}
+
+const char *
+Headers_Map_Item::header (void) const
+{
+ return this->header_;
+}
+
+const char *
+Headers_Map_Item::value (void) const
+{
+ return this->value_;
+}
+
+Headers_Map_Item &
+Headers_Map::operator[] (const char * const header)
+{
+ Headers_Map_Item *item_ptr;
+
+ item_ptr = this->find (header);
+
+ if (item_ptr == NULL)
+ item_ptr = this->place (header);
+
+ return *item_ptr;
+}
+
+const Headers_Map_Item &
+Headers_Map::operator[] (const char * const header) const
+{
+ Headers_Map_Item *item_ptr;
+ Headers_Map *mutable_this = (Headers_Map *)this;
+
+ item_ptr = this->find (header);
+
+ if (item_ptr == NULL)
+ item_ptr = mutable_this->place (header);
+
+ return *item_ptr;
+}
+
+int
+Headers_Map::mapped (const char * const header) const
+{
+ int result = this->find (header) != NULL;
+
+ return result;
+}
+
+Headers_Map_Item *
+Headers_Map::find (const char * const header) const
+{
+ Headers_Map *const mutable_this = (Headers_Map *) this;
+
+ mutable_this->garbage_.header_ = header;
+#if 0
+ Headers_Map_Item *mi_ptr = (Headers_Map_Item *)
+ ::bsearch (&this->garbage_,
+ this->map_,
+ this->num_headers_,
+ sizeof (Headers_Map_Item),
+ Headers_Map::compare);
+#else
+ int i = 0;
+ int j = this->num_headers_;
+
+ while (i < j-1)
+ {
+ int k = (i+j)/2;
+ if (Headers_Map::compare (&this->garbage_, this->map_+k) < 0)
+ j = k;
+ else
+ i = k;
+ }
+
+ Headers_Map_Item *mi_ptr = mutable_this->map_ + i;
+ if (Headers_Map::compare (&this->garbage_, mi_ptr) != 0)
+ mi_ptr = 0;
+#endif
+
+ mutable_this->garbage_.header_ = 0;
+
+ return mi_ptr;
+}
+
+Headers_Map_Item *
+Headers_Map::place (const char *const header)
+{
+ this->garbage_.header_ = ACE_OS::strdup (header);
+
+ int i = this->num_headers_++;
+ ACE_OS::free ((void *) this->map_[i].header_);
+ ACE_OS::free ((void *) this->map_[i].value_);
+ this->map_[i].header_ = 0;
+ this->map_[i].value_ = 0;
+ Headers_Map_Item temp_item;
+
+ while (i > 0)
+ {
+ if (Headers_Map::compare (&this->garbage_,
+ &this->map_[i - 1]) > 0)
+ break;
+
+ this->map_[i].header_ = this->map_[i - 1].header_;
+ this->map_[i].value_ = this->map_[i - 1].value_;
+ this->map_[i - 1].header_ = 0;
+ this->map_[i - 1].value_ = 0;
+
+ i--;
+ }
+
+ this->map_[i].header_ = this->garbage_.header_;
+ this->map_[i].value_ = this->garbage_.value_;
+
+ this->garbage_.header_ = 0;
+
+ return &this->map_[i];
+}
+
+int
+Headers_Map::compare (const void *item1,
+ const void *item2)
+{
+ Headers_Map_Item *a, *b;
+ int result;
+
+ a = (Headers_Map_Item *) item1;
+ b = (Headers_Map_Item *) item2;
+
+ if (a->header_ == 0 || b->header_ == 0)
+ {
+ if (a->header_ == 0 && b->header_ == 0)
+ result = 0;
+ else if (a->header_ == 0)
+ result = 1;
+ else
+ result = -1;
+ }
+ else
+ result = ACE_OS::strcasecmp (a->header_, b->header_);
+
+ return (result < 0) ? -1 : (result > 0);
+}
diff --git a/ACE/apps/JAWS/server/Parse_Headers.h b/ACE/apps/JAWS/server/Parse_Headers.h
new file mode 100644
index 00000000000..f5d564d8d0b
--- /dev/null
+++ b/ACE/apps/JAWS/server/Parse_Headers.h
@@ -0,0 +1,121 @@
+/* -*- c++ -*- */
+// Hey, Emacs! This is a C++ file!
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// jaws
+//
+// = FILENAME
+// Parse_Headers.h
+//
+// = AUTHOR
+// James Hu
+//
+// ============================================================================
+
+#ifndef PARSE_HEADERS_H
+#define PARSE_HEADERS_H
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class Headers_Map_Item
+{
+friend class Headers_Map;
+friend class Headers;
+
+private:
+ Headers_Map_Item (void);
+ ~Headers_Map_Item (void);
+
+ // operator const char * (void) const;
+ Headers_Map_Item &operator= (char *);
+ Headers_Map_Item &operator= (const char *);
+ Headers_Map_Item &operator= (const Headers_Map_Item &);
+
+public:
+ const char *header (void) const;
+ const char *value (void) const;
+
+private:
+ const char *header_;
+ const char *value_;
+};
+
+class Headers_Map
+ // = TITLE
+ // Map textual headings to header values (e.g. "Subject:" maps to
+ // "Re: My left foot"
+{
+public:
+ Headers_Map (void);
+ ~Headers_Map (void);
+
+ Headers_Map_Item &operator[] (const char *const header);
+ const Headers_Map_Item &operator[] (const char *const header) const;
+
+ enum
+ {
+ MAX_HEADERS = 100
+ };
+
+ int mapped (const char *const header) const;
+
+private:
+ Headers_Map_Item *find (const char *const header) const;
+ Headers_Map_Item *place (const char *const header);
+ static int compare (const void *item1, const void *item2);
+
+private:
+ Headers_Map_Item map_[MAX_HEADERS];
+ Headers_Map_Item garbage_;
+
+ int num_headers_;
+};
+
+class Headers
+ // = TITLE
+ // A general mechanism to parse headers of Internet text headers.
+ //
+ // = DESCRIPTION
+ // Allow interesting headers to be inserted and later associated
+ // with values. This implementation assumes the parsing of headers
+ // will be done from ACE_Message_Blocks.
+{
+public:
+ Headers (void);
+ ~Headers (void);
+
+ void recognize (const char *const header);
+
+ void parse_header_line (char *const header_line);
+
+ int complete_header_line (char *const header_line);
+ // -1 -> end of line but not complete header line
+ // 0 -> no end of line marker
+ // 1 -> complete header line
+
+ int end_of_headers (void) const;
+
+ enum
+ {
+ MAX_HEADER_LINE_LENGTH = 8192
+ };
+
+ Headers_Map_Item &operator[] (const char *const header);
+ const Headers_Map_Item &operator[] (const char *const header) const;
+
+private:
+ int end_of_line (char *&line, int &offset) const;
+
+private:
+ Headers_Map map_;
+ int done_;
+};
+
+#endif /* PARSE_HEADERS_H */
diff --git a/ACE/apps/JAWS/server/README b/ACE/apps/JAWS/server/README
new file mode 100644
index 00000000000..27f0a0e3a8d
--- /dev/null
+++ b/ACE/apps/JAWS/server/README
@@ -0,0 +1,228 @@
+# -*- text -*-
+# Hey, Emacs! This is a TEXT file.
+
+--------------------------
+README for the JAWS server
+--------------------------
+
+This is the README file for the JAWS server.
+
+CONTENTS
+
+1. Compiling
+ a. UNIX
+ b. Windows NT 4.0
+
+2. Executing
+ a. svc.conf parameters
+ b. General Info
+
+3. Limitations
+
+4. Acknowledgements
+
+5. New additions
+
+------------
+1. Compiling
+------------
+
+1a. Compiling under UNIX.
+
+ Assuming that the environment variable ACE_ROOT is set
+correctly, and that you are using GNU make, compiling should simply
+involve:
+
+ $ cd $ACE_ROOT/apps/JAWS/server
+ $ make clean
+ $ make depend
+ $ make
+
+This will produce an executable named ``main''.
+
+1b. Compiling under Windows NT 4.0.
+
+ Assuming you are using a recent version of Microsoft
+Visual C++, you can use the jaws.mdp file located in
+$ACE_ROOT/apps/JAWS/server to build JAWS.
+
+
+------------
+2. Executing
+------------
+
+2a. svc.conf parameters.
+
+ To run JAWS, simply execute "main". It loads the HTTP server
+from the file named in the ``svc.conf'' file. The ``svc.conf'' file
+itself contains documentation about the load line. It supports the
+following command-line arguments:
+
+ -p port Start JAWS on the specified port.
+ -n num_threads Use num_threads as the maximum number of threads.
+ -f thr_flag Can be used multiple times to set thread
+ creation flags:
+ THR_BOUND -> bound threads
+ THR_DAEMON -> daemonized threads
+ THR_DETACHED -> detached threads
+ THR_NEW_LWP -> increase concurrency level
+ -t thr_strategy Use one of the following strategies:
+ POOL -> thread pool
+ PER_REQUEST -> thread-per-request
+ THROTTLE -> thread-per-request with throttling
+ -i io_strategy Use one of the following strategies:
+ SYNCH -> synchronous I/O
+ ASYNCH -> asynchronous I/O
+ -b backlog Backlog value for listen ().
+
+2b. General Information
+
+ By default, JAWS will used port 5432 with 5 threads and apply
+the synchronous thread pool strategy. Unless set, the default backlog
+value is equal the value of the maximum number of threads.
+
+ JAWS also responds to several environment variables. This is
+a temporary feature which will be replaced by a more general
+configuration file similar to NCSA httpd's. The environment variables
+are:
+ JAWS_DOCUMENT_ROOT
+ This is the starting point the server will use to look
+ for files.
+ Default value: the current directory of the server.
+
+ JAWS_CGI_PATH
+ This is intended to be a ``:'' delimited list of paths
+ (similar to your regular PATH environment variable) which
+ describes the possible locations for CGI binaries.
+ Default value: Any directory named ``cgi-bin''.
+
+ JAWS_USER_DIR
+ This is the name of the subdirectory in a users home
+ directory which contains publicly available WWW documents.
+ Default value: ``.www''.
+
+ JAWS_DIR_INDEX
+ The name of the file which is sent, if present, when the URL
+ leads to a directory.
+ Default value: ``index.html''.
+
+ You may test the server by executing telnet, opening a
+connection to the server machine on the server port. For instance:
+
+ $ telnet machinename 5432
+ Trying ###.###.###.###...
+ Connected to machinename.your.domain
+ Escape character is '^]'.
+ GET /main.cpp
+ // main.cpp
+ //...
+
+ Note that if you use an HTTP/1.0 get request, then you have
+to hit return twice before the file will be sent. E.g.,
+
+ $ telnet machinename 5432
+ Trying ###.###.###.###...
+ Connected to machinename.your.domain
+ Escape character is '^]'.
+ GET /main.cpp HTTP/1.0
+
+ // main.cpp
+ //...
+
+ Where applicable, JAWS will perform ``~'' expansion for home
+directories of usernames.
+
+
+-----------
+3. Features
+-----------
+
+(a) JAWS supports full HTTP/1.0 responses.
+
+(b) JAWS support CGI scripts on UNIX.
+
+(c) JAWS parses request headers. The mechanism can be used to parse
+ headers from a variety of text based protocols (e.g., SNMP and
+ NNTP).
+
+(d) Optimized filecaching.
+
+--------------
+4. Limitations
+--------------
+
+The following are TODO items for JAWS:
+
+status|task
+------+-----------------------
+ | (a) JAWS will support HTTP/1.1 eventually, including
+ | persistent connections.
+ |
+ | (b) JAWS can be more aggressive with its threading strategies,
+ | such as:
+ | (*) parallelize HTTP protocol processing, similar to
+ | PHTTPD.
+ | (*) prioritize threads to give more important requests
+ | more execution time.
+ | (*) apply throttling, similar to THTTPD.
+ |
+ | (c) JAWS will support a general protocol content filtering
+ | mechanism which will be used to replace the existing CGI
+ | support implementation.
+ |
+
+Questions, comments, corrections, suggestions are welcome. Please
+feel free to send me any such correspondence.
+
+James Hu <jxh@cs.wustl.edu>
+
+-------------------
+4. Acknowledgements
+-------------------
+
+ My partners in crime for this endeavor include:
+
+ Eastman-Kodak, Rochester N.Y.
+ and Object Technologies, Inc. For providing funding for this
+ research.
+
+ Dr. Douglas Schmidt For being my advisor, and
+ convincing my sponsors to fund
+ me.
+
+ Irfan Pyarali For porting JAWS to NT, and
+ for designing and implementing
+ the JAWS IO mechanism.
+
+ Sumedh Mungee For writing the benchmark
+ client, and performing the
+ UNIX benchmarks.
+
+ Tim Harrison For his comments, advice, and
+ help in designing the IO
+ mechanism used by JAWS.
+
+-----------------------
+5. Additions
+-----------------------
+
+The need arose to have JAWS not perform any file caching. We added this
+functionality and provided a new cmd line option -c with params NO_CACHE/CACHE.
+
+This capability is to be used with the RepositoryManager in CIAO.
+
+In its current design the RepositoryManager (RM) need a collocated HTTP server.
+When RM istalls packages, it unpacks them so that the separate files are accessible to
+ZIP unaware entities like JAWS. JAWS is used to serve the libraries in the package to the
+various deamons that might be interested in them, e.g. the NodeApplicationManager.
+
+The problem with using file caching reveals itself during the deletePackage operation of
+the RM. When the RM attempts to delete a file which was previously accessed via JAWS a
+is currently in the file cache the call fails and the file remains on the filesystem
+indefinitely. If the file is cached with a ACE_NOMAP option is is not stored in a file
+map and it is deleted upon server termination. The OS handles that. Althoguh this might
+or might not be OK (depending on how it scales) there is an additional problem because
+JAWS and the ACE_Filecache_Handle class used do not provide enough functionality to deal
+with the ACE_NOMAP case. I believe that ACE_NOMAP option was probably never used.
+
+To overcome the above problems we added the no caching functionality in JAWS.
diff --git a/ACE/apps/JAWS/server/jaws.auth b/ACE/apps/JAWS/server/jaws.auth
new file mode 100644
index 00000000000..e3c51f7eac8
--- /dev/null
+++ b/ACE/apps/JAWS/server/jaws.auth
@@ -0,0 +1,2 @@
+jxh:nonsense
+bill:no nonsense
diff --git a/ACE/apps/JAWS/server/main.cpp b/ACE/apps/JAWS/server/main.cpp
new file mode 100644
index 00000000000..4f319f02727
--- /dev/null
+++ b/ACE/apps/JAWS/server/main.cpp
@@ -0,0 +1,57 @@
+// $Id$
+
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Filecache.h"
+
+#include "HTTP_Server.h"
+#include "ace/OS_main.h"
+#include "ace/OS_NS_signal.h"
+
+ACE_RCSID(server, main, "$Id$")
+
+ACE_STATIC_SVC_REQUIRE(HTTP_Server)
+
+#ifdef ACE_HAS_SIG_C_FUNC
+extern "C"
+{
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+ // call exit() so that static destructors get called
+static void
+handler (int)
+{
+ delete (ACE_Filecache *) ACE_Filecache::instance ();
+ ACE_OS::exit (0);
+}
+
+#ifdef ACE_HAS_SIG_C_FUNC
+}
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+// This is the driver entry point into JAWS. It is possible to use
+// JAWS as an ACE Service, as well.
+
+int
+main (int argc, char *argv[])
+{
+ ACE_Service_Config daemon;
+
+ ACE_OS::signal (SIGCHLD, SIG_IGN);
+
+ // SigAction not needed since the handler will shutdown the server.
+ ACE_OS::signal (SIGINT, (ACE_SignalHandler) handler);
+ ACE_OS::signal (SIGUSR2, (ACE_SignalHandler) handler);
+
+ if (daemon.open (argc, argv, ACE_DEFAULT_LOGGER_KEY, 0) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), 1);
+
+ // The configured service creates threads, and the
+ // server won't exit until the threads die.
+
+ // Run forever, performing the configured services until we receive
+ // a SIGINT.
+
+
+ return 0;
+}
diff --git a/ACE/apps/JAWS/server/server.mpc b/ACE/apps/JAWS/server/server.mpc
new file mode 100644
index 00000000000..a79e488cf83
--- /dev/null
+++ b/ACE/apps/JAWS/server/server.mpc
@@ -0,0 +1,36 @@
+// -*- MPC -*-
+// $Id$
+
+project(JAWS) : acelib {
+ sharedname = JAWS
+ dynamicflags = ACE_BUILD_SVC_DLL
+ requires += ace_filecache
+ avoids += uses_wchar
+ avoids += ace_for_tao
+
+ Source_Files {
+ HTTP_Server.cpp
+ HTTP_Config.cpp
+ HTTP_Handler.cpp
+ HTTP_Helpers.cpp
+ JAWS_Pipeline.cpp
+ JAWS_Concurrency.cpp
+ HTTP_Request.cpp
+ HTTP_Response.cpp
+ Parse_Headers.cpp
+ IO.cpp
+ }
+}
+
+project(JAWS_server) : aceexe {
+ exename = main
+ after += JAWS
+ libs += JAWS
+ requires += ace_filecache
+ avoids += uses_wchar
+ avoids += ace_for_tao
+
+ Source_Files {
+ main.cpp
+ }
+}
diff --git a/ACE/apps/JAWS/server/svc.conf b/ACE/apps/JAWS/server/svc.conf
new file mode 100644
index 00000000000..fdba6ab9c76
--- /dev/null
+++ b/ACE/apps/JAWS/server/svc.conf
@@ -0,0 +1,49 @@
+#
+# -p port number
+# -n threads in the server
+# -f thread activation flags
+# = THR_BOUND
+# = THR_DAEMON
+# = THR_DETACHED
+# = THR_NEW_LWP
+# -t threading strategy
+# = POOL -> thread pool
+# = PER_REQUEST -> thread per request
+# = THROTTLE -> thread per request with throttling
+# -i I/O strategy
+# = SYNCH
+# = ASYNCH
+# -b backlog value for listen ()
+# -c caching: NO_CACHE or CACHE
+#
+#
+# Thread Pool, 20 unbound threads
+# This is the baseline
+static HTTP_Server "HTTP_Server -p 5432 -n 20 -i SYNCH -t POOL -b 50 -f THR_NEW_LWP"
+#
+#
+# Start a baseline server without caching
+#static HTTP_Server "HTTP_Server -p 5432 -n 20 -i SYNCH -t POOL -b 50 -f THR_NEW_LWP -c NO_CACHE"
+#
+#
+# Thread Pool, 40 threads
+#static HTTP_Server "HTTP_Server -p 5432 -n 40 -i SYNCH -t POOL -b 50 -f THR_NEW_LWP -f THR_BOUND"
+#
+#
+# Thread-per-request, unlimited number of threads
+#static HTTP_Server "HTTP_Server -p 5432 -i SYNCH -t PER_REQUEST -b 50 -f THR_NEW_LWP"
+#
+#
+# Throttling, 40 threads
+#static HTTP_Server "HTTP_Server -p 5432 -n 40 -i SYNCH -t THROTTLE -b 50 -f THR_NEW_LWP"
+#
+
+#
+# Example for using HTTP_Server as a dynamic service
+#
+# For NT.
+#dynamic HTTP_Server Service_Object * ./jaws.exe:_make_HTTP_Server() "HTTP_Server -p 5432 -n 20 -i SYNCH -t POOL -b 50 -f THR_NEW_LWP"
+
+#
+# For UNIX platforms.
+#dynamic HTTP_Server Service_Object * ./main:_make_HTTP_Server() "HTTP_Server -p 5432 -n 20 -i SYNCH -t POOL -b 50 -f THR_NEW_LWP"
diff --git a/ACE/apps/JAWS/server/test.cgi b/ACE/apps/JAWS/server/test.cgi
new file mode 100755
index 00000000000..936afcf0d3c
--- /dev/null
+++ b/ACE/apps/JAWS/server/test.cgi
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo Content-type: text/plain
+echo
+
+echo args -- $*
+env
+echo Done!
+exit 0