// distribution boxbackup-0.11.1 (svn version: 2821_2827)
// Box Backup, http://www.boxbackup.org/
// 
// Copyright (c) 2003-2010, Ben Summers and contributors.
// All rights reserved.
// 
// Note that this project uses mixed licensing. Any file with this license
// attached, or where the code LICENSE-DUAL appears on the first line, falls
// under this license. See the file COPYING.txt for more information.
// 
// This file is dual licensed. You may use and distribute it providing that you
// comply EITHER with the terms of the BSD license, OR the GPL license. It is
// not necessary to comply with both licenses, only one.
// 
// The BSD license option follows:
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  
// 3. Neither the name of the Box Backup nor the names of its contributors may
//    be used to endorse or promote products derived from this software without
//    specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// [http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29]
// 
// The GPL license option follows:
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// 
// [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC4]
// --------------------------------------------------------------------------
//
// File
//		Name:    HTTPServer.cpp
//		Purpose: HTTP server class
//		Created: 26/3/04
//
// --------------------------------------------------------------------------

#include "Box.h"

#include <stdio.h>

#include "HTTPServer.h"
#include "HTTPRequest.h"
#include "HTTPResponse.h"
#include "IOStreamGetLine.h"

#include "MemLeakFindOn.h"


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::HTTPServer()
//		Purpose: Constructor
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
HTTPServer::HTTPServer()
	: mTimeout(20000)	// default timeout leaves a little while for clients to get the second request in.
{
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::~HTTPServer()
//		Purpose: Destructor
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
HTTPServer::~HTTPServer()
{
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::DaemonName()
//		Purpose: As interface, generic name for daemon
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
const char *HTTPServer::DaemonName() const
{
	return "generic-httpserver";
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::GetConfigVerify()
//		Purpose: As interface -- return most basic config so it's only necessary to
//				 provide this if you want to add extra directives.
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
const ConfigurationVerify *HTTPServer::GetConfigVerify() const
{
	static ConfigurationVerifyKey verifyserverkeys[] = 
	{
		HTTPSERVER_VERIFY_SERVER_KEYS(ConfigurationVerifyKey::NoDefaultValue) // no default addresses
	};

	static ConfigurationVerify verifyserver[] = 
	{
		{
			"Server",
			0,
			verifyserverkeys,
			ConfigTest_Exists | ConfigTest_LastEntry,
			0
		}
	};
	
	static ConfigurationVerifyKey verifyrootkeys[] = 
	{
		HTTPSERVER_VERIFY_ROOT_KEYS
	};

	static ConfigurationVerify verify =
	{
		"root",
		verifyserver,
		verifyrootkeys,
		ConfigTest_Exists | ConfigTest_LastEntry,
		0
	};

	return &verify;
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::Run()
//		Purpose: As interface.
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
void HTTPServer::Run()
{
	// Do some configuration stuff
	const Configuration &conf(GetConfiguration());
	HTTPResponse::SetDefaultURIPrefix(conf.GetKeyValue("AddressPrefix"));

	// Let the base class do the work
	ServerStream<SocketStream, 80>::Run();
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::Connection(SocketStream &) 
//		Purpose: As interface, handle connection
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
void HTTPServer::Connection(SocketStream &rStream)
{
	// Create a get line object to use
	IOStreamGetLine getLine(rStream);

	// Notify dervived claases
	HTTPConnectionOpening();

	bool handleRequests = true;
	while(handleRequests)
	{
		// Parse the request
		HTTPRequest request;
		if(!request.Receive(getLine, mTimeout))
		{
			// Didn't get request, connection probably closed.
			break;
		}
	
		// Generate a response
		HTTPResponse response(&rStream);
		
		try
		{
			Handle(request, response);
		}
		catch(BoxException &e)
		{
			char exceptionCode[256];
			::sprintf(exceptionCode, "%s (%d/%d)", e.what(),
				e.GetType(), e.GetSubType());
			SendInternalErrorResponse(exceptionCode, response);
		}
		catch(...)
		{
			SendInternalErrorResponse("unknown", response);
		}
		
		// Keep alive?
		if(request.GetClientKeepAliveRequested())
		{
			// Mark the response to the client as supporting keepalive
			response.SetKeepAlive(true);
		}
		else
		{
			// Stop now
			handleRequests = false;
		}
	
		// Send the response (omit any content if this is a HEAD method request)
		response.Send(request.GetMethod() == HTTPRequest::Method_HEAD);
	}

	// Notify derived classes
	HTTPConnectionClosing();
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::SendInternalErrorResponse(const char*,
//			 HTTPResponse&)
//		Purpose: Generates an error message in the provided response
//		Created: 26/3/04
//
// --------------------------------------------------------------------------
void HTTPServer::SendInternalErrorResponse(const std::string& rErrorMsg,
	HTTPResponse& rResponse)
{
	#define ERROR_HTML_1 "<html><head><title>Internal Server Error</title></head>\n" \
			"<h1>Internal Server Error</h1>\n" \
			"<p>An error, type "
	#define ERROR_HTML_2 " occured when processing the request.</p>" \
			"<p>Please try again later.</p>" \
			"</body>\n</html>\n"

	// Generate the error page
	// rResponse.SetResponseCode(HTTPResponse::Code_InternalServerError);
	rResponse.SetContentType("text/html");
	rResponse.Write(ERROR_HTML_1, sizeof(ERROR_HTML_1) - 1);
	rResponse.IOStream::Write(rErrorMsg.c_str());
	rResponse.Write(ERROR_HTML_2, sizeof(ERROR_HTML_2) - 1);
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::HTTPConnectionOpening()
//		Purpose: Override to get notifications of connections opening
//		Created: 22/12/04
//
// --------------------------------------------------------------------------
void HTTPServer::HTTPConnectionOpening()
{
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    HTTPServer::HTTPConnectionClosing()
//		Purpose: Override to get notifications of connections closing
//		Created: 22/12/04
//
// --------------------------------------------------------------------------
void HTTPServer::HTTPConnectionClosing()
{
}


