#include "StdAfx.h"
#include "04WebServer.h"
#include "connection.h"
#include "threadskeleton.h"
#include "server.h"
#include "dateutility.h"
#include "intervaltimer.h"
#include "StringCompare.h"
#include "Dir.h"
#include "subprocess.h"
#include "SSLSocket.h"

#include "systemresponse.h"
#include "normalresponse.h"
#include "directoryresponse.h"
#include "fileresponse.h"
#include "cgiresponse.h"
#include "ssiresponse.h"

#include "davpropfindresponse.h"
#include "fileputresponse.h"
#include "filedeleteresponse.h"
#include "filemoveresponse.h"
#include "optionsresponse.h"
#include "keyswapstring.h"


CConnection::CConnection(CServer *server,CMySocket *socket)
: m_interrupt(this)
{
	//	変数初期化
	m_server = server;
	m_maxKeepAliveTime = m_server->m_setting.GetConfig("Basic::KeepAliveTime",20) * 1000;
	m_keepAlive = m_server->m_setting.GetConfig("Basic::EnableKeepAlive",0);

	//	ソケット設定
	m_socket = socket;

	//	スレッド開始
	if(StartThread())
		throw CConnectionException("スレッドの開始に失敗しました");
}

CConnection::~CConnection(void)
{
	EndThread();

	delete m_socket;
	m_socket = NULL;
}

//!	タイムアウト
void CConnection::OnTimeOut()
{
	//	切断
	m_socket->Close();

	CTimeOut::OnTimeOut();
}

//!	中断
void CConnection::Break()
{
	//	切断
	m_socket->Close();

	CThreadSkeleton::Break();
}

/*!
	接続処理
*/
void CConnection::ThreadMain()
{
	DWORD		lastAccess = GetTickCount();
	CIPAddress	peer = m_socket->GetPeerAddres();

	//	SSL関連の処理
	if(SSLTask())
		return;

	while(1)
	{
		//	アクセスは？
		char temp;
		if(m_socket->CanRecv() && m_socket->Peek(&temp,1) && !m_socket->IsDisconnect())
		{
			//	新しい環境生成
			CConfigAccess context = NewContext();

			//	１リクエストの処理を行う
			try
			{
				//	初期化
				m_sendSize = 0;
				m_recvSize = 0;
				m_recvDataSize = 0;

				//	接続処理
				int KeepAlive = OneRequest(context);

				//	転送量記録
				UpdateTransSize(context);

				//	正常に終了したのでサーバログに出力
				WriteLog(context);

				//	環境削除
				DeleteContext(context);

				//	切断？
				if(KeepAlive == 0)
					break;
			}
			catch(CServerFatalException e)
			{
				//	転送量記録
				UpdateTransSize(context);

				//	切断の必要のあるエラーが発生したので、ログにエラーを出力
				context.SetConfig("Info",e.m_info);
				WriteLog(context);

				//	環境削除
				DeleteContext(context);
				return;
			}

			//	アクセスがあったので、KeepAlive時間を延長
			lastAccess = GetTickCount();
		}
		else
		{
			//	マターリ
			Sleep(20);
		}

		//	切断した？
		if(m_socket->IsDisconnect())
			break;

		//	KeepAliveは有効ではない？
		if(m_keepAlive==0)
			break;

		//	keepAliveタイムアウト？
		if(lastAccess + m_maxKeepAliveTime < GetTickCount())
			break;
	}

	m_socket->Close();
}

/*!
	SSL関連の処理を行う
*/
int CConnection::SSLTask()
{
	//	SSL?
	if(m_socket->IsSSL())
	{
		//	SSLネゴシエーション
		if(((CSSLSocket *)m_socket)->SSLAccept())
			return(-1);
	}
	return(0);
}

/*!
	１リクエストの処理を行う
*/
int CConnection::OneRequest(CConfigAccess context)
{
	/*
		リクエストの受信と解析を行う
	*/
	//	ホスト情報
	context.SetConfig("Host",(CString)m_socket->GetPeerAddres());

	//	ヘッダーの受信
	CString		header = RecvHeader();

	//	リクエストの解析
	CRequest	request(header,context.GetAccess("RequestInfo"));

	//	ターゲットホスト情報
	context.SetConfig("TargetHost",request.m_options.GetConfig("Host",""));

	//	パスの解析
	CAlias		alias(request.m_uriObject,request.m_options.GetConfig("Host",""),m_server->m_setting);

	//	帯域幅管理
	CBandWidthReference	bandRef(m_server->GetCBandWidthMgr(),m_socket->GetPeerAddres(),context.GetConfig("ThreadName",""));

	//	レスポンス
	CResponse *use = NULL;

	//	Keep-Aliveの解析
	int KeepAlive;
	if(request.m_options.GetConfig("Connection","",TRUE).CompareNoCase("keep-alive") == 0)
		KeepAlive = 1;
	else
		KeepAlive = 0;


	//	サーバーエラースコープ(500)
	try
	{
		//	サーバーレスポンススコープ(301,404 etc...)
		try
		{
			//	標準レスポンススコープ
			try
			{
				//	ユーザー認証・接続制限など、アクセス制限をチェックする
				CheckAccess(context,request,alias,bandRef);

				//	WebDAV
				WebDAV(context,request,alias);

				//	移動？
				if(alias.IsMove())
				{
					CSystemResponse *move = new CSystemResponse(m_server,context,alias.GetMoveTo() + " に移動してください",301);
					move->m_responseOptions.SetConfig("Location",alias.GetMoveTo());
					throw move;
				}

				//	ディレクトリ表示？
				if(alias.IsDirectory())
					throw new CDirectoryResponse(m_server,context,request,alias);

				//	CGI?
				CGI(context,request,alias);

				//	SSI?
				SSI(context,request,alias);

				//	最終はファイル
				throw new CFileResponse(m_server,context,request,alias);
			}
			catch(CNormalResponse *response)
			{
				//	例外発生時、上のスコープで削除
				use = response;

				//	レスポンス送信
				SendResponse(context,request,alias,bandRef,response);
				delete response;

				//	メッセージ
				context.SetConfig("Info","正常に終了しました");

				//	正常終了
				return KeepAlive;
			}
		}
		catch(CSystemResponse *response)
		{
			//	下のスコープのデータを削除
			if(use != NULL)
				delete use;

			//	例外発生時、上のスコープで削除
			use = response;

			//	レスポンス送信
			SendResponse(context,request,alias,bandRef,response);
			
			//	メッセージ
			context.SetConfig("Info",response->GetInfo());

			delete response;

			//	正常終了
			return KeepAlive;
		}
	}
	catch(CServerFatalException e)
	{
		//	下のスコープのデータを削除
		if(use != NULL)
			delete use;

		//	致命的サーバエラー
		SendFatalError(e.m_info);

		//	エラー登録
		context.SetConfig("ResponseInfo::ResponseCode",500);
		context.SetConfig("ResponseInfo::ResponseText",CResponse::GetHTTPResponseString(500));

		//	上に投げる
		throw CServerFatalException(e.m_info);
	}
	catch(CMemoryException *err)
	{
		err->Delete();

		//	下のスコープのデータを削除
		if(use != NULL)
			delete use;

		//	致命的サーバエラー
		SendFatalError("リクエストの処理中に、メモリ不足が発生しました");

		//	エラー登録
		context.SetConfig("ResponseInfo::ResponseCode",500);
		context.SetConfig("ResponseInfo::ResponseText",CResponse::GetHTTPResponseString(500));

		//	上に投げる
		throw CServerFatalException("リクエストの処理中に、メモリ不足が発生しました");
	}

	//	ここには来ない筈
	ASSERT(0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	レスポンス作成
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
 *	アクセスが有効かチェック
 */
void CConnection::CheckAccess(CConfigAccess &context,CRequest &request,CAlias &alias,CBandWidthReference &bandRef)
{
	//	HTTPS不許可？
	if(m_socket->IsSSL() && alias.GetPathOptions().GetConfig("AcceptHTTPS",1)==0)
		throw new CSystemResponse(m_server,context,"HTTPS からのアクセスは、許可されていません",403);

	//	HTTP不許可？
	if(m_socket->IsSSL()==0 && alias.GetPathOptions().GetConfig("AcceptHTTP",1)==0)
		throw new CSystemResponse(m_server,context,"HTTP からのアクセスは、許可されていません",403);

	//	キック？
	if(CheckKickHost(context,request,alias))
		throw new CSystemResponse(m_server,context,"ホスト " + context.GetConfig("Host","") + " からのアクセスは、許可されていません",403);
		
	//	接続制限チェック
	if(bandRef.IsLimitOver())
		throw new CSystemResponse(m_server,context,"１ホストの最大接続数を超えました",503);

	//	隠しファイルは無効？
	if(alias.GetPathOptions().GetConfig("EnableHiddenFile",0) == 0 && alias.IsHidden())
		throw new CSystemResponse(m_server,context,"このファイル・ディレクトリへのアクセスは、許可されていません",403);

	//	ユーザーチェック
	CheckUser(context,request,alias);
}

/*!
 *	WebDAV
 */
void CConnection::WebDAV(CConfigAccess &context,CRequest &request,CAlias &alias)
{
	//	Options
	if(request.m_method == "OPTIONS")
		throw new COptionsResponse(m_server,context,request,alias);

	//	WebDAVは有効?
	if(alias.GetPathOptions().GetConfig("EnableWebDAV",0))
	{
		if(request.m_method == "PROPFIND")
			throw new CDAVPropfindResponse(m_server,context,request,alias);
		else if(request.m_method == "PROPPATCH")
			throw CServerFatalException("サポートしていません");
		else if(request.m_method == "LOCK")
			throw CServerFatalException("サポートしていません");
		else if(request.m_method == "UNLOCK")
			throw CServerFatalException("サポートしていません");
	}

	//	書き込みは有効か？
	if(alias.GetPathOptions().GetConfig("EnableWrite",0))
	{
		if(request.m_method == "PUT")
			throw new CFilePutResponse(m_server,context,request,alias);
		else if(request.m_method == "MKCOL")
			throw new CFilePutResponse(m_server,context,request,alias);
		else if(request.m_method == "DELETE")
			throw new CFileDeleteResponse(m_server,context,request,alias);
		else if(request.m_method == "COPY")
			throw new CFileMoveResponse(m_server,context,request,alias);
		else if(request.m_method == "MOVE")
			throw new CFileMoveResponse(m_server,context,request,alias);
	}
}


/*!
	CGI
*/
void CConnection::CGI(CConfigAccess &context,CRequest &request,CAlias &alias)
{
	//	ファイルはあるのか？
	if(!alias.IsExist()  && !alias.IsExtarExist())
		return;

	//	CGIは許可されているのか？
	if(alias.GetPathOptions().GetConfig("EnableSSICGI",0))
	{
		//	通常
		CString command = CSubProcess::GetCGICommand(m_server,alias.GetTarget(),request.m_queryDecoded);

		//	エクストラパス
		if(command.IsEmpty() && alias.IsExtarExist())
			command = CSubProcess::GetCGICommand(m_server,alias.GetExtraTarget(),request.m_queryDecoded);

		if(!command.IsEmpty())
		{
			context.SetConfig("ScriptCommand",command);
			throw new CCGIResponse(m_server,context,request,alias,m_interrupt);
		}
	}
}


/*!
	SSI
*/
void CConnection::SSI(CConfigAccess &context,CRequest &request,CAlias &alias)
{
	//	ファイルはあるのか？
	if(!alias.IsExist())
		return;

	//	SSIは許可されているのか？
	if(alias.GetPathOptions().GetConfig("EnableSSICGI",0))
	{
		//	拡張子の取得
		CString	ext = CDir::PathToExt(alias.GetTarget());

		//	設定リストを取得
		CConfigAccess	ssiSetting = m_server->m_setting.GetAccess("SSI");
		CStringArray	ssiList;
		ssiSetting.GetAllKey(ssiList);

		//	各設定を処理
		for(int i=0;i<ssiList.GetSize();i++)
		{
			if(ext.CompareNoCase(ssiSetting.GetConfig(ssiList[i],"")) == 0)
				throw new CSSIResponse(m_server,context,request,alias,m_interrupt);
		}
	}
}

/*!
	キックするホストかチェック
*/
int CConnection::CheckKickHost(CConfigAccess &context,CRequest &request,CAlias &alias)
{
	CConfigAccess	kick = alias.GetPathInfo().GetAccess("Kick");
	CString			hostIP = m_socket->GetPeerAddres();

	//	有効？
	if(alias.GetPathOptions().GetConfig("EnableHostKick",0))
	{
		//	まずは禁止されているかチェック
		CConfigAccess	denied = kick.GetAccess("Denied");
		CStringArray	list;
		denied.GetAllKey(list);

		for(int i=0;i<list.GetSize();i++)
		{
			if(CStringCompare::WildCompare(denied.GetConfig(list[i],""),hostIP))
				return(1);
		}

		//	許可されているかチェック
		CConfigAccess	accept = kick.GetAccess("Accept");
		accept.GetAllKey(list);

		for(int i=0;i<list.GetSize();i++)
		{
			if(CStringCompare::WildCompare(accept.GetConfig(list[i],""),hostIP))
				return(0);
		}

		return(1);
	}

	return(0);
}


/*!
 *	ユーザーのチェック
 *
 */
void CConnection::CheckUser(CConfigAccess &context,CRequest &request,CAlias &alias)
{
	if(alias.GetPathOptions().GetConfig("EnableAuthenticate",0))
	{
		CString	username = request.m_user;
		if(alias.GetPathOptions().GetConfig("EnableWebDAV",0))
		{
			//	WindowsXP 対策
			int index = username.Find("\\");
			if(index != -1)
				username = username.Mid(index+1);
		}

		if(CheckUser(username,request.m_passwd,alias)==0)
		{
			CSystemResponse *move = new CSystemResponse(m_server,context,"認証が必要です",401);
			CString str;
			str.Format("Basic realm=\"%s\"",alias.GetPathInfo().GetConfig("Info",""));
			move->m_responseOptions.SetConfig("WWW-Authenticate",str);
			throw move;
		}
	}
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	レスポンス処理
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
 *	ヘッダーの受信
 *
 */
CString CConnection::RecvHeader()
{
	//	この関数内でタイムアウトする可能性がある
	TIMEOUT_SCOPE();

	CString	header;
	int		index = 0;

	//	ヘッダーを受信
	while(1)
	{
		//	受信データのチェック
		if(m_socket->PeekString(header)<0)
			throw CServerFatalException("ヘッダー受信中に切断もしくはネットワークエラーが発生しました");

		//	終了をチェック
		index = header.Find("\r\n\r\n");
		if(index != -1)
			break;
		
		//	異常なヘッダを排除
		if(m_socket->GetInRecvBuf() > 32000)
			throw CServerFatalException("異常なヘッダーを受信しました");

		//	切断とか、中断とかの割り込みは？
		if(m_interrupt.IsInterrupt())
			throw CServerFatalException("ヘッダー受信中に" + m_interrupt.GetInterruptInfo());

		Sleep(20);
	}

	//	ヘッダー解析
	if(m_socket->RecvString(header,index + 4)<0)
			throw CServerFatalException("ヘッダー受信中に切断もしくはネットワークエラーが発生しました");

	//	受信サイズ
	m_recvSize += header.GetLength();

	return(header);
}

/*!
	レスポンスの処理
*/
void CConnection::SendResponse(CConfigAccess &context,CRequest &request,CAlias &alias,CBandWidthReference &bandRef,CResponse *response)
{
	//	メッセージ
	context.SetConfig("Info","レスポンスデータの前処理中...");

	//	レスポンス生成準備
	response->PreCreateResponse();

	//	レスポンスボディーの受信
	RecvData(context,request,alias,bandRef,response);

	//	レスポンスを生成する
	context.SetConfig("Info","レスポンスデータの生成中...");
	response->CreateResponse();

	//	レスポンス情報の取得
	CConfigAccess responseInfo = response->GetResponseInfo();
	CConfigAccess responseOptions = responseInfo.GetAccess("Options");

	//	長さ情報の取得
	__int64 length = response->GetResponseSize();
	responseOptions.SetConfig("Content-Length",length);

	//	ヘッダの生成
	CString header = MakeHeaderString(responseInfo);

	//	メッセージ
	context.SetConfig("Info","ヘッダーの送信中です...");

	//	ヘッダの送信
	if(m_socket->SendString(header)<0)
		throw CServerFatalException("ヘッダー送信中に切断もしくはネットワークエラーが発生しました");

	//	ヘッダサイズ
	m_sendSize += header.GetLength();

	//	ボディー送信
	SendData(context,request,alias,bandRef,response,length);
}

/*!
	リクエストボディーを受信
*/
void CConnection::RecvData(CConfigAccess &context,CRequest &request,CAlias &alias,CBandWidthReference &bandRef,CResponse *response)
{
	context.SetConfig("Info","データの受信を開始しています...");

	//	この関数内でタイムアウトする可能性がある
	TIMEOUT_SCOPE();

	//	受信サイズは？
	__int64 len = _atoi64(request.m_options.GetConfig("Content-Length","0",TRUE));
	__int64	orgLen;

	//	2回目の呼び出しの可能性を考慮(残りのデータのみを取得する)
	len -= m_recvDataSize;
	orgLen = len;

	//	リミットの設定
	bandRef.SetRecvLimit(alias.GetPathOptions().GetConfig("EnableBandWidthLimit",0));

	//	受信
	int					recv;
	CBuffer				data;
	CBandWidthLimit		limiter;
	CIntervalTimer		timer(1000);
	while(len > 0)
	{
		//	PeekBufに読み込んでみる
		if(m_socket->RecvToPeekBuf() < 0)
			throw CServerFatalException("データ受信中に切断もしくはネットワークエラーが発生しました");

		//	PeekBufが一杯か、残りサイズまで全部読み込んだ
		if(m_socket->PeekBufIsFull() || m_socket->InPeekBuf() >= len)
		{
			int inPeekBuf = m_socket->InPeekBuf();

			data.ReSize(inPeekBuf);
			if(len > inPeekBuf)
				recv = m_socket->Recv(data,inPeekBuf);
			else
				recv = m_socket->Recv(data,(int)len);

			if(recv < 0)
				throw CServerFatalException("データ受信中に切断もしくはネットワークエラーが発生しました");

			data.ReSize(recv);
			response->SetNextData(data);
			len -= recv;
			m_recvSize += recv;
			m_recvDataSize += recv;

			//	帯域制限によるウェイト
			Delay(limiter.GetWaitTick(bandRef.GetCurrentRecvLimit(),recv));
			limiter.OneTracsEnd();

			//	処理状況
			if(timer)
			{
				int limit = bandRef.GetCurrentRecvLimit();

				CString	str;
				if(!limit)
					str.Format("受信中 : %I64dK/%I64dK [%I64d%%] (%0.1fK/Sec)",orgLen - len,orgLen,(orgLen - len) * 100 / orgLen,(double)limiter.GetCurSpeed()/1024.0);
				else
					str.Format("受信中 : %I64dK/%I64dK [%I64d%%] (%0.1fK/S, Limit: %0.1fK/S)",orgLen - len,orgLen,(orgLen - len) * 100 / orgLen,(double)limiter.GetCurSpeed()/1024.0,(double)limit/1024.0);
				context.SetConfig("Info",str);
			}

			TIMEOUT_RESET();
		}
		else
			Sleep(20);	//	マターリ

		//	切断とか、中断とかの割り込みは？
		if(m_interrupt.IsInterrupt())
			throw CServerFatalException("データ受信中に" + m_interrupt.GetInterruptInfo());
	}

	//	リミット解除
	bandRef.SetRecvLimit(0);
}

/*!
	レスポンスボディーを送信
*/
void CConnection::SendData(CConfigAccess &context,CRequest &request,CAlias &alias,CBandWidthReference &bandRef,CResponse *response,__int64 length)
{
	context.SetConfig("Info","データの送信を開始しています...");

	//	この関数内でタイムアウトする可能性がある
	TIMEOUT_SCOPE();

	//	リミットの設定
	bandRef.SetSendLimit(alias.GetPathOptions().GetConfig("EnableBandWidthLimit",0));


	//	Bodyの送信
	CBuffer			data(65536);
	CBandWidthLimit	limiter;
	CIntervalTimer	timer(1000);
	__int64			sended = 0;
	while(1)
	{
		TIMEOUT_RESET();
		int size = response->GetNextData(data);

		if(size <= 0)
			break;



		if(data.GetSize() > 0)
		{
			if(m_socket->Send(data,size)<0)
			{
				throw CServerFatalException("データ送信中に切断もしくはネットワークエラーが発生しました");
			}
			m_sendSize += size;
			sended += size;
		}


		//	切断とか、中断とかの割り込みは？
		if(m_interrupt.IsInterrupt())
			throw CServerFatalException("データ送信中に" + m_interrupt.GetInterruptInfo());

		//	帯域制限によるウェイト
		Delay(limiter.GetWaitTick(bandRef.GetCurrentSendLimit(),size));
		limiter.OneTracsEnd();

		//	処理状況
		if(timer)
		{
			int limit = bandRef.GetCurrentSendLimit();

			CString	str;
			if(!limit)
				str.Format("送信中 : %I64dK/%I64dK [%I64d%%] (%0.1fK/Sec)",sended,length,sended * 100 / length,(double)limiter.GetCurSpeed()/1024.0);
			else
				str.Format("送信中 : %I64dK/%I64dK [%I64d%%] (%0.1fK/S, Limit: %0.1lfK/S)",sended,length,sended * 100 / length,(double)limiter.GetCurSpeed()/1024.0,(double)limit/1024.0);
			context.SetConfig("Info",str);
		}

	}

	//	リミット解除
	bandRef.SetRecvLimit(0);

}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	補助関数
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
	ヘッダの生成
*/
CString CConnection::MakeHeaderString(CConfigAccess responseInfo)
{
	CConfigAccess responseOptions = responseInfo.GetAccess("Options");
	CString	header,line;

	//	レスポンスライン
	line.Format("HTTP/1.1 %s\r\n",responseInfo.GetConfig("ResponseText","500 Internal Server Error"));
	header += line;

	//	オプションライン
	CStringArray	keyList;
	responseOptions.GetAllKey(keyList);
	for(int i=0;i<keyList.GetSize();i++)
	{
		line.Format("%s: %s\r\n",keyList[i],responseOptions.GetConfig(keyList[i],""));
		header += line;
	}

	//	CGI用ヘッダ
	CString cgiHeader = responseInfo.GetConfig("CGIHeader","");
	header += cgiHeader;
	header += "\r\n";

	return(header);
}


/*!
	致命的エラーの処理
*/
void CConnection::SendFatalError(CString info)
{
	//	この関数内でタイムアウトする可能性がある
	TIMEOUT_SCOPE();

	CString	body;
	body.Format("<HTML><HEAD>"\
				"<TITLE>500 Internal Server Error</TITLE>"\
				"<meta http-equiv=\"Content-Type\" content=\"text/html;charset=Shift_JIS\"></HEAD>\n"\
				"<BODY><H1>Error : 500 Internal Server Error</H1>"\
				"<PRE>%s</PRE>"\
				"<HR><ADDRESS>04WebServer/"SERVER_VER"</ADDRESS>"\
				"</BODY></HTML>",info);

	CString	head;
	head.Format("HTTP/1.0 500 Internal Server Error\r\n"\
				"Server: 04WebServer/"SERVER_VER"\r\n"\
				"Content-Type: text/html\r\n"\
				"Connection: Close\r\n"\
				"Content-length: %d\r\n"\
				"\r\n",body.GetLength());

	m_socket->SendString(head);
	m_socket->SendString(body);
	m_socket->Close();
}


/*!
	新しいコンテキストの取得
*/
CConfigAccess CConnection::NewContext()
{
	//	ワークスペース作成
	CString	name;
	name.Format("Thread_%04x",m_server->GetNewID());

	CConfigAccess	ret = m_server->m_threadContext.GetAccess(name);
	ret.SetConfig("ThreadName",name);

	//	作成日時設定
	CConfigAccess	date = ret.GetAccess("StartTime");
	date.Copy(GetDate());

	//	メッセージ
	ret.SetConfig("Info","初期化中です...");

	//	タイプ
	if(m_socket->IsSSL())
	{
		ret.SetConfig("Protocol","https");
	}
	else
	{
		ret.SetConfig("Protocol","http");
	}

	return(ret);
}

/*!
	ログ
*/
void CConnection::WriteLog(CConfigAccess &context)
{
	//	置き換えもとソースを設定
	CKeySwapString	swapper;
	CString			format = m_server->m_setting.GetConfig("Log::LogFormatNoTime","[%Time%] <%Host%> (%RecvSize%,%SendSize%) [%Info%] %Method% %Object%");
	swapper.SetString(format);

	CConfigAccess	request = context.GetAccess("RequestInfo");
	CConfigAccess	response = context.GetAccess("ResponseInfo");

	//	Userが設定されていない場合 "-" に置き換え
	if(request.GetConfig("User","").IsEmpty())
		swapper.Swap("User","-");

	//	コンテキスト情報
	swapper.Swap(context);

	//	標準情報
	swapper.Swap(request);
	swapper.Swap(response);

	swapper.Swap(request.GetAccess("Options"));
	swapper.Swap(response.GetAccess("Options"));

	//	改行を削除
	CString	logLine = swapper.GetString("-");
	logLine.Replace("\n","_");
	logLine.Replace("\r","_");

	m_server->m_log.WriteLog("%s",logLine);
}


/*!
	コンテキストの破棄
*/
void CConnection::DeleteContext(CConfigAccess context)
{
	CString	name = context.GetConfig("ThreadName","");
	int max = m_server->m_setting.GetConfig("Log::MaxThreadLog",10);

	//	日付の取得
	CConfigAccess	date = context.GetAccess("EndTime");
	date.Copy(GetDate());

	if(max > 0)
	{
		//	ロック
		LOCK_CONFIG(m_server->m_threadContextLog);

		//	領域のコピー
		CConfigAccess	log = m_server->m_threadContextLog.GetAccess(name);
		log.Copy(context);

		//	ログ数の調整
		if(m_server->m_threadContextLog.GetSubNodeCount() > max)
		{
			CStringArray	array;
			m_server->m_threadContextLog.GetAllSubNode(array);
			m_server->m_threadContextLog.DeleteNode(array[0]);
		}
	}

	//	環境の削除
	m_server->m_threadContext.DeleteNode(name);
}


//	転送量を記録
void CConnection::UpdateTransSize(CConfigAccess &context)
{
	//	転送量登録
	m_server->AddTrans(m_sendSize,m_recvSize);

	//	サイズの記録
	context.SetConfig("RecvSize",m_recvSize);
	context.SetConfig("SendSize",m_sendSize);
	context.SetConfig("Size",m_recvSize + m_sendSize);
}



/*!
 *	日付取得
 *
 *	@param	detail	1:詳細有効
 *	@return			環境領域
 */
CConfigAccess CConnection::GetDate(int detail)
{
	//	時刻環境領域を取得
	CConfigAccess date = m_date.GetAccess("Date");
	date.Clear();

	//	時刻
	CTime	time=CTime::GetCurrentTime();
	date.SetConfig("Date",time.Format("%Y/%m/%d"));
	date.SetConfig("Time",time.Format("%H:%M:%S"));
	date.SetConfig("GMT",CDateUtility::GetGMTString(time));

	if(detail)
	{
		date.SetConfig("Year",time.Format("%Y"));
		date.SetConfig("Month",time.Format("%m"));
		date.SetConfig("Day",time.Format("%d"));
		date.SetConfig("DayOfWeek",time.Format("%w"));

		date.SetConfig("MonthString",time.Format("%b"));
		date.SetConfig("DayOfWeekString",time.Format("%a"));

		date.SetConfig("Hour",time.Format("%H"));
		date.SetConfig("Minute",time.Format("%M"));
		date.SetConfig("Second",time.Format("%S"));

	}
	return(date);
}


/*!
 *	ユーザーのチェック
 */
int CConnection::CheckUser(CString userName,CString passwd,CAlias alias)
{
	CConfigAccess	pathUser = alias.GetPathInfo().GetAccess("Users");
	CConfigAccess	enableUser = m_server->m_setting.GetAccess("User::Enable");

	//	検索
	CStringArray	userList;
	pathUser.GetAllKey(userList);
	for(int i=0;i<userList.GetSize();i++)
	{
		if(pathUser.GetConfig(userList[i],"") == userName)
			goto next;
	}
	return 0;

next:

	//	検索
	enableUser.GetAllSubNode(userList);
	for(int i=0;i<userList.GetSize();i++)
	{
		CConfigAccess user = enableUser.GetAccess(userList[i]);
		if(user.GetConfig("User","") == userName && user.GetConfig("Passwd","") == passwd)
			return 1;
	}
	return 0;
}


/*!
 *	ウェイト
 */
void CConnection::Delay(int tick)
{
	DWORD	endTick = GetTickCount() + tick;

	while(!m_interrupt.IsInterrupt())
	{
		int subTick = endTick - GetTickCount();
		
		if(subTick <= 0)
		{
			break;
		}
		else if(subTick < 20)
		{
			Sleep(subTick);
			break;
		}
		else
			Sleep(20);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	割り込み管理クラス
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CConnectionInterrupt::CConnectionInterrupt(CConnection *connection)
{
	m_connection = connection;
}

CConnectionInterrupt::CConnectionInterrupt(CConnectionInterrupt &other)
{
	m_connection = other.m_connection;
	m_interruptInfo = other.m_interruptInfo;
}

//	割り込みか？
int CConnectionInterrupt::IsInterrupt()
{
	//	タイムアウトチェック
	if(m_connection->IsTimeOut())
	{
		m_interruptInfo = "タイムアウトしました";
		return(1);
	}

	//	切断チェック
	if(m_connection->m_socket->IsDisconnect())
	{
		m_interruptInfo = "切断しました";
		return(1);
	}

	//	中断チェック
	if(m_connection->GetBreak())
	{
		m_interruptInfo = "中断しました";
		return(1);
	}

	return(0);
}

//	オペレータ
CConnectionInterrupt::operator int()
{
	return(IsInterrupt());
}

//	情報取得
CString CConnectionInterrupt::GetInterruptInfo()
{
	return(m_interruptInfo);
}

