C++ベースのLightweightなHTTPサーバー
| Rev. | Time | Author | Message |
|---|---|---|---|
| ca54241 | 2013-11-26 00:14:12 | Michio Hirai | master [BugFix] Forgot to add dtor code (where it has to have a ... |
| 94c5015 | 2013-11-26 00:11:44 | Michio Hirai | [Function] First addition of http HttpSocketManager class... |
| 8fbd88f | 2013-11-23 22:55:50 | Michio Hirai | [Function] Change cm::IOVectorChain class template implem... |
| 21a0a6e | 2013-11-22 18:50:37 | Michio Hirai | [Refactor] Change a way to wait for an appropriate thread... |
| fa67399 | 2013-11-22 18:32:22 | Michio Hirai | [Function] New addition of cm::Condition class |
| a7815c9 | 2013-11-19 00:47:31 | Michio Hirai | [BugFix] Fix some compilation issues in Linux port and al... |
| 4204b59 | 2013-11-18 02:19:45 | Michio Hirai | [Refactor] Change some README text. |
| 6ca1a69 | 2013-11-18 02:16:01 | Michio Hirai | [Function] New support of no arugument type message handl... |
| a9d9e70 | 2013-11-17 19:32:01 | Michio Hirai | [Function] Change cm::Mutex implementation to support rec... |
| d4dd7af | 2013-11-17 19:30:50 | Michio Hirai | [Refactor] Change unit test implementation (from memcpy t... |
| Name | Rev. | Time | Author | Message |
|---|---|---|---|---|
| master | ca54241 | 2013-11-26 00:14:12 | Michio Hirai | [BugFix] Forgot to add dtor... |
============================================================
FlyingHttpServer - lightweight HTTP server based on C++
------------------------------------------------------------
by smg_ykz
============================================================
1. Introduction
This software is intended to be a lightweight C++ based HTTP server.
Although there are number of open-source based HTTP server softwares available,
what this software is trying to address is the following.
(a) By making use of the OOP design and generic/meta- programming techniques/idioms,
it tries to keep the software some sort of extensible, and yet easy-to-maintain.
(b) It tries to be of help in case some embedded device has to deploy HTTP server.
So in this sense, conventional CGI support which may be useful for scripting language
such as Perl, Python, Ruby etc. should be some low priority.
(c) It tries to help programmers who are involved in this software get some hints on
their daily programming.
2. Dependency
In order to keep the software good quality, it is essential that the software don't have
pretty much dependency on the other software components. The following are software
components which are identified as essential.
(a) CMake - http://www.cmake.org
This is the build system we are going to use.
(b) Googlemock - http://code.google.com/p/googlemock/
For the purpose of performing unit testing, we use this mocking framework. This software
component also includes Googletest.
3. How to proceed with the things
Quality over Time - based on this belief, we are (perhaps only I'm...?) supposed to develop
this software. That indicates that the project will be slowly kept on going, which might not
attract users... Excuse me, in advance.
We are going to maintain the source code tree so that this software can be built succesfully
by multiple comipler collections. The followings are the compilation collections which are
being used for the build.
GNU GCC (running under MAC OS X)
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)
CLANG (running under MAC OS X)
Apple clang version 3.0 (tags/Apple/clang-211.12) (based on LLVM 3.0svn)
Target: x86_64-apple-darwin11.4.2
Thread model: posix
GNU GCC (running under CentOS 5.0)
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-50)
GNU GCC44 (running under CentOS 5.0)
gcc44 (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)
Before going into the very HTTP server development, firstly we are going to develop and/or
maintain the framework component, which should help the software some sort of good quality
etc.
4. (Sub-)Packages
In this softeware, packages are explicitly divided into different namespaces. The following
briefly shows what kind of packages are there in the software.
=======================================================================================================
[mt] -> Meta-programming library
This is the software package mainly focuses on providing meta/generic-programming components.
In that sense, almost all of them should be in the form of header files so that client code
can instantiate the module along with its parameterized type.
Basically I like to use so-called Typelist very much whose idea was elaborated in the authoritative
book named as 'Modern C++ Design - by Andrei Alexandrescu'. See how we can manipulate 'type' in
compilation time in the unit test code 'inc/test/mt_typelist_test.cpp'. (TODO:
put some more unit tests there)
[File inc/mt_static_assert.h]
This gives you the way to express a compile time assertion. You will be able to simply write a statement something like this.
STATIC_ASSERT(statement_which_is_true_in_compilation_time);
[File inc/mt_array_length.h]
This gives you the simple way to count number of elements in an array. Assume that we have the following
statement,
char_t buffer[128];
then the ARRAY_LENGTH macro should return 128. Since this will simply use compile time calculation,
there is no conputation const in run-time.
STATIC_ASSERT(ARRAY_LENGTH(buffer) == 128);
[File mt_auto_ptr.h]
This gives you std::auto_ptr equivalent. The reason why we don't use std::auto_ptr is that it has the following issues.
1) std::auto_ptr doesn't incorporate 'checked delete' idiom. Depending on the way to write code, it may have a chance that the parameterized type to put into the std::auto_ptr is forward-declared without having the exact declaration. In such case, the std::auto_ptr may have quite subtle issue that is difficult to identify. In order to avoid such issue, we use this mt::AutoPtr class template instead of std::auto_ptr.
2) reset() and set() member function. The std::auto_ptr class template has reset() member function that will be used for the purpose of releasing the object and also for the purpose of setting the new object. This nature sometimes introduces subtle issue in case that the class design of the paramterized type doesn't allow multiple objects to be present at the same time.
std::auto_ptr<Type> obj(new Type);
obj.reset(new Type); // This statement allow the originall Type object and another Type object to be present in a short period of time....
In order to avoid such issue, mt::AutoPtr class template distinguish these 2 operations into multiple member methods of reset() and set(). In order to release the object, release() member method should be used and this should not be used for the purpose of putting another object. For the latter purpose, the other member method set() is to be used.
[File mt_mpl.h]
This gives you basic set of meta-programming class template. <TODO: further explanation here>
[File mt_range.h]
This gives you the simply way to get the first element of iterator from container/array as well as the end element of iterator from them.
begin() -- This will give the iteretor of the begin element taking the container/array in the argument.
cbegin() -- This will give the const iterator of the begin element taking the container/array in the argument.
end() -- This will give the iterator of the end element taking the container/array in the argument.
cend() -- This will give the const iterator of the end element taking the container/array in the argument.
[File mt_shim_clear_memory.h]
This gives you simply way to clear all the container/array. In case that some STL compliant container is put in this mt::clearMemory() shim function argument, clear() method will be invoked as a result of calling mt::clearMemory() function. In case that some arrayis put in this function argument, all the elements in the array are zero-ed as a result of calling mt::clearMemory() function.
[File mt_tuple.h]
=======================================================================================================
[cm] -> Common library
This is the software package that supports various 'aspects'. So in that sense, this should play
a role as core framework library under this software.
=======================================================================================================
cm_thread (libcm_thread.a)
Thread library which wraps several pthread APIs. Along with this
libary you will be able to also use 'inc/cm_thread_specific_data.h'
template library so that you can handle Thread-Specific Data storage per 'types'. See the unit
test code in 'cm/test/cm_thread_specific_data_test.cpp' for some hint.
This library also provides with 'mutex' which is useful to protect a certain 'resource' appropriately
under multi-thread environment. The way to use cm::Mutex is only allowed via nested 'Lock' class as
follows.
// Object instantiation
cm::Mutex mutex;
{
cm::Mutex::Lock lock(mutex);
// mutex is locked as long as this 'Lock' object is present.
}
It is recommended not to use this thread library directly. Instead it is recommended to use
cm::ThreadEventDriven class template so you don't need to take care much about thread management.
For more details, please take a look at cm/test/cm_thread_event_driven_test.cpp unit test code.
The only thing you are supposed to construct is to create some new class to declare/define some
action when some 'Event' happens as follows.
class SampleMessageHandler
{
public:
SampleMessageHandler(cm::SocketIf* socket)
: socket_if_(*socket)
{
cm::Event::tsdInstance().addHandlerRead(*this, &SampleMessageHandler::handleRead, socket_if_);
}
~SampleMessageHandler()
{
cm::Event::tsdInstance().delHandlerRead(socket_if_);
}
static const char_t* getName() { return "sample_message_handler_thread"; }
bool handleRead(cm::SocketIf& sock)
{
// implement operation here to read some data from socket etc..
}
private:
cm::SocketIf& socket_if_;
};
if you could prepare for the above handler class, then you can easily create the event-driven thread
as follows.
cm::ThreadEventDriven<SampleMessageHandler, cm::SocketIf> thread(&socket);
// The created thread above is present as long as the 'thread' class object is present...
=======================================================================================================
cm_event (libcm_event.a)
Event library which currently wraps epoll APIs (for Linux) and kqueue,kevent
APIs (for xxxBSD). This will be helpful to construct a event-driven basis programming styles. As
for Event types which can be used in conjunction with the Event class will be also provided in future.
=======================================================================================================
cm_socket (libcm_socket.a)
Socket library which wraps socket APIs. It supports Unix domain socket
(PF_LOCAL) and IPv4 socket (PF_INET). As for classes responsible for instantiation (factory),
cm::SocketServer and cm::SocketClient classes are introduced. These classes respectively have accept()
and connect() methods, which instantiate the cm::Socket class object whose lifetime is managed under
mt::AutoPtr<cm::SocketIf> RAII smart pointer.
-------------------------------------------------------------------------------------------------------
[cm::SocketIf class (Interface class)]
This is just an interface class which represents (network) socket. This interface class provides read
and write operation from/to the socket. It also provides 'clone' method, which may be helpful for unit
test purpose etc..
Although this interface class provides getFD() const method to get to know the exact socket descriptor
number, it is not recommend to use this public method in the client code directly. This getFD() member
method will be used by cm::Event class so that it can get the stimulus to realize event-driven callback
mechanism along with its getFD() free-function.
Basically the cm::SocketIf class family will hold RAII(RRID) idiom. Once this class object is
destructed, socket descriptor which is bound to this class object will be closed accordingly. This is
the way we realize the resource management of socket descriptors. If you need to give away its resource
control of the socket descriptor, release() public method will be used, which returns its socket
descriptor number and then notify its class object that it is no longer necessary to conduct the
resource desctruction.
<Public methods>
bool read(size_t& bytes_read, void* buf, size_t size_to_read)
read() attempts 'size_to_read' bytes of data from the (network) socket referenced by the class
object to the buffer pointed by buf. If successful, 'true' will be returned along with the number
of succesfully read data in 'bytes_read' argument. If not successful, 'false' will be returned.
bool write(size_t& bytes_written, const void* buf, size_t size_to_write)
write() attempts 'size_to_write' bytes of data to the (networ) socket referenced by the class
object from the buffer pointed by buf. If successful, 'true' will be returned along with the number
of successfully written data in 'bytes_written' argument. If not successful, 'false' will be
returned.
int getFD() const
getFD() simply gives the exact socket descriptor number. This function is not recommended to be
used as this will impair object oriented design paradigm. The reason why this public method is
prepared is that this is essential to make use of epoll-, kevent/kqueue- based callback mechanism
as an entire framework. This public method will be used by cm::Event class for merely for this
purpose.
int release()
Similar to the above getFD() const method, this gives he exact socket descriptor number. However,
the purpose of using this method is totally different than the above.
There is some case that you would need to enforce a cm::SocketIf class object to give away its
resource management of socket descriptor. For example, this frame library also provies
cm::VectorSocket class which enables gather-write (writev) operation towards the network
socket. Although these two class objects don't have the same abstract class in common, these two
object can be interchangeable i.e. when you firstly create some cm::SocketIf object and then pass
this object refererence to instantiate the cm::VectorSocket class object by the following ctor
statement.
cm::SocketIf& socket_if = ...; // Assume that this socket_if is bound to some concrete
// cm::SocketIf class object.
cm::VectorSocket vector_socket(socket_if);
The above statement internally handles this release() method to transfer its resource control from
cm::SocketIf to cm::VectorSocket so we don't need to be bothered by any double-free sort of issue.
This is how this release() method will be used.
mt::AutoPtr<SocketIf> clone(int fd) const
This clone() method will be used when you would like to realize some 'prototype pattern' style
of programming. For the details of what is prototype pattern, please refer to authoritative book
such as Design Pattern by GoF.
[cm::Socket class (Concrete class)]
Basically this concreate class provides with the implementation of what the above interface class
(cm::SocketIf) declare.