Skip to content

Commit

Permalink
Merge pull request #18 from JadeMatrix/v0.8.1
Browse files Browse the repository at this point in the history
v0.8.1
  • Loading branch information
JadeMatrix authored Dec 27, 2017
2 parents 6ec5adf + d877a56 commit cc8928b
Show file tree
Hide file tree
Showing 12 changed files with 446 additions and 532 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required( VERSION 3.9 )
cmake_minimum_required( VERSION 3.6 )

set( CMAKE_CXX_STANDARD 11 )
set( CMAKE_CXX_STANDARD_REQUIRED ON )
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![stable version](https://img.shields.io/github/release/JadeMatrix/SHOW.svg?label=stable)](https://github.com/JadeMatrix/SHOW/releases/latest)
[![latest version](https://img.shields.io/github/release/JadeMatrix/SHOW/all.svg?label=latest)](https://github.com/JadeMatrix/SHOW/releases)
[![Documentation Status](https://readthedocs.org/projects/show-cpp/badge/?version=v0.8.0)](http://show-cpp.readthedocs.io/en/v0.8.0/?badge=v0.8.0)
[![Documentation Status](https://readthedocs.org/projects/show-cpp/badge/?version=v0.8.1)](http://show-cpp.readthedocs.io/en/v0.8.1/?badge=v0.8.1)

SHOW is an idiomatic library for standalone webserver applications written for modern C++. SHOW is simple in the same way the standard library is simple — it doesn't make any design decisions for the programmer, instead offering a set of primitives for building an HTTP web application. Everything — when to serve, what requests to accept, even whether to send a response at all — is completely up to the programmer.

Expand Down
8 changes: 8 additions & 0 deletions doc/Connection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Connection
The port of the connected client

.. cpp:function:: const std::string& server_address() const
The address of the server handling the connection

.. cpp:function:: unsigned int server_port() const
The port of the server handling the connection

.. cpp:function:: int timeout() const
Get the current timeout of this connection, initially inherited from the server the connection is created from
Expand Down
4 changes: 1 addition & 3 deletions doc/Tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ Another thing to keep in mind is that HTTP/1.1 — and HTTP/1.0 with an extensio
Sending Responses
=================

Sending responses is slightly more complex than reading basic requests, aside from the error handling which should wrap both.

Say you want to send a "Hello World" message for any incoming request. First, start with a string containing the response message::
Sending responses is slightly more involved than reading basic requests. Say you want to send a "Hello World" message for any incoming request. First, start with a string containing the response message::
std::string response_content = "Hello World";

Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
# The short X.Y version.
version = u'0.8'
# The full version, including alpha/beta/rc tags.
release = u'0.8.0'
release = u'0.8.1'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
111 changes: 50 additions & 61 deletions examples/echo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ void handle_POST_request( show::request& request )

if( request.unknown_content_length() )
{
// Always require a Content-Length header for this application
// For this example, be safe and reject any request with no Content-
// Length header
show::response response(
request.connection(),
show::http_protocol::HTTP_1_0,
Expand All @@ -35,13 +36,17 @@ void handle_POST_request( show::request& request )
}
else
{
// Since we're echoing the request content, just replicate the Content-
// Length header
headers[ "Content-Length" ].push_back(
// Header values must be strings
std::to_string( request.content_length() )
);

// Replicate the Content-Type header of the request if it exists,
// otherwise assume plain text
// otherwise use the default MIME type recommended in the HTTP
// specification, RFC 2616 §7.2.1:
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
auto content_type_header = request.headers().find( "Content-Type" );
if(
content_type_header != request.headers().end()
Expand All @@ -51,18 +56,20 @@ void handle_POST_request( show::request& request )
content_type_header -> second[ 0 ]
);
else
headers[ "Content-Type" ].push_back( "text/plain" );
headers[ "Content-Type" ].push_back( "application/octet-stream" );

// This is not the most computationally-efficient way to accomplish
// this, see
// This is just the simplest way to read a whole streambuf into a
// string, not the most the fastest; see
// https://stackoverflow.com/questions/3203452/how-to-read-entire-stream-into-a-stdstring
std::string message = std::string(
std::istreambuf_iterator< char >( ( std::streambuf* )&request ),
std::istreambuf_iterator< char >( &request ),
{}
);

show::response response(
request.connection(),
// Just handling one request per connection in this example, so
// respond with HTTP/1.0
show::http_protocol::HTTP_1_0,
{
200,
Expand All @@ -75,80 +82,62 @@ void handle_POST_request( show::request& request )
}
}


int main( int argc, char* argv[] )
{
std::string host = "::"; // IPv6 loopback (0.0.0.0 in IPv4)
unsigned int port = 9090; // Some random higher port
int timeout = 10; // Connection timeout in seconds

try
{
show::server test_server(
host,
port,
timeout
);

while( true )
show::server test_server(
host,
port,
timeout
);

while( true )
try
{
show::connection connection( test_server.serve() );

try
{
show::connection connection( test_server.serve() );
show::request request( connection );

try
if( request.method() == "POST" )
{
show::request request( connection );

if( request.method() == "POST" )
{
handle_POST_request( request );
}
else
{
show::response response(
request.connection(),
show::http_protocol::HTTP_1_0,
{
405,
"Method Not Allowed"
},
{ server_header }
);
}
handle_POST_request( request );
}
catch( const show::connection_timeout& ct )
else
{
std::cout
<< "timed out waiting on client, closing connection"
<< std::endl
;
break;
show::response response(
request.connection(),
show::http_protocol::HTTP_1_0,
{
405,
"Method Not Allowed"
},
{ server_header }
);
}
}
catch( const show::connection_timeout& ct )
catch( const show::connection_interrupted& ct )
{
std::cout
<< "timed out waiting for connection, looping..."
<< "client "
<< connection.client_address()
<< " disconnected or timed out, closing connection"
<< std::endl
;
}
}
catch( const std::exception& e )
{
std::cerr
<< "uncaught std::exception in main(): "
<< e.what()
<< std::endl
;
return -1;
}
catch( ... )
{
std::cerr
<< "uncaught non-std::exception in main()"
<< std::endl
;
return -1;
}
}
catch( const show::connection_timeout& ct )
{
std::cout
<< "timed out waiting for connection, looping..."
<< std::endl
;
}

return 0;
}
110 changes: 46 additions & 64 deletions examples/fileserve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ std::string guess_mime_type( const std::string& path )
else if( extension == ".mp3" )
return "audio/mpeg3";
else
// Default MIME type for raw binary
// Default MIME type recommended in the HTTP specification, RFC 2616
// §7.2.1:
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
return "application/octet-stream";
}

Expand Down Expand Up @@ -339,81 +341,61 @@ int main( int argc, char* argv[] )
int timeout = 10; // Connection timeout in seconds
std::string message = "Hello World!";

try
{
show::server test_server(
host,
port,
timeout
);

while( true )
show::server test_server(
host,
port,
timeout
);

while( true )
try
{
show::connection connection( test_server.serve() );

try
{
show::connection connection( test_server.serve() );
show::request request( connection );

try
{
show::request request( connection );

// Only accept GET requests
if( request.method() != "GET" )
{
show::response response(
request.connection(),
show::http_protocol::HTTP_1_0,
{ 501, "Not Implemented" },
{ server_header }
);
continue;
}

handle_GET_request( request, argv[ 1 ] );
}
catch( const show::client_disconnected& cd )
// Only accept GET requests
if( request.method() != "GET" )
{
std::cout
<< "client "
<< connection.client_address()
<< " disconnected, closing connection"
<< std::endl
;
}
catch( const show::connection_timeout& ct )
{
std::cout
<< "timed out waiting on client "
<< connection.client_address()
<< ", closing connection"
<< std::endl
;
show::response response(
request.connection(),
show::http_protocol::HTTP_1_0,
{ 501, "Not Implemented" },
{ server_header }
);
continue;
}

handle_GET_request( request, argv[ 1 ] );
}
catch( const show::client_disconnected& cd )
{
std::cout
<< "client "
<< connection.client_address()
<< " disconnected, closing connection"
<< std::endl
;
}
catch( const show::connection_timeout& ct )
{
std::cout
<< "timed out waiting for connection, looping..."
<< "timed out waiting on client "
<< connection.client_address()
<< ", closing connection"
<< std::endl
;
}
}
catch( const std::exception& e )
{
std::cerr
<< "uncaught std::exception in main(): "
<< e.what()
<< std::endl
;
return -1;
}
catch( ... )
{
std::cerr
<< "uncaught non-std::exception in main()"
<< std::endl
;
return -1;
}
}
catch( const show::connection_timeout& ct )
{
std::cout
<< "timed out waiting for connection, looping..."
<< std::endl
;
}

return 0;
}
Loading

0 comments on commit cc8928b

Please sign in to comment.