#include "StdAfx.h"
#include "request.h"
#include "connection.h"
#include "UrlUtility.h"
#include "Base64.h"

CRequest::CRequest(CString &header,CConfigAccess requestInfo)
{
	if(ParseHeader(header,requestInfo))
		throw CServerFatalException("異常なヘッダーを受信しました");
}

CRequest::~CRequest(void)
{
}


/*!
 *	ヘッダー解析
 *
 */
int CRequest::ParseHeader(CString &header,CConfigAccess requestInfo)
{
	CString	line;


	//	リクエスト取り出し
	if(GetLine(header,line)==0)
		return(-1);
	
	//	メソッド
	if(GetToken(line,m_method," ")==0)
		return(-1);

	//	URI
	if(GetToken(line,m_uri," ")==0)
		return(-1);

	//	URIObject
	m_uriObject = CUrlUtility::GetUrlObject(m_uri);
	m_uriObject = CUrlUtility::DecodeUrl(m_uriObject);

	//	Query
	m_query = CUrlUtility::GetQuery(m_uri);
	m_queryDecoded = CUrlUtility::Decode(m_query);

	//	バージョン
	if(GetToken(line,m_version,"/")==0)
		return(-1);
	if(line.GetLength() == 0)
		return(-1);
	m_version = line;


	//	高速化のため、ロック
	LOCK_CONFIG(requestInfo);


	//	オプションヘッダー取得
	CConfigAccess options = requestInfo.GetAccess("Options");
	CString	key;
	while(1)
	{
		if(GetLine(header,line)==0)
			break;

		//	key
		if(GetToken(line,key,": ")==0)
			continue;

		//	data
		if(line.GetLength() == 0)
			continue;

		options.SetConfig(key,line);
	}

	//	ユーザーとパスワード
	CString	encoded = options.GetConfig("Authorization","");
	if(encoded.GetLength() > 6)
	{
		if(encoded.Left(6).CompareNoCase("Basic ") == 0)
		{
			encoded = encoded.Mid(6);
			CString	userpass = CBase64::Decode64(encoded);

			int	index = userpass.Find(":");
			if(index != -1)
			{
				m_user = userpass.Left(index);
				m_passwd = userpass.Mid(index + 1);
			}
		}
	}

	//	環境へ設定
	requestInfo.SetConfig("Method",m_method);
	requestInfo.SetConfig("URL",m_uri);
	requestInfo.SetConfig("Object",m_uriObject);
	requestInfo.SetConfig("Version",m_version);
	requestInfo.SetConfig("Query",m_query);
	requestInfo.SetConfig("QueryDecoded",m_queryDecoded);
	requestInfo.SetConfig("User",m_user);
	requestInfo.SetConfig("Passwd",m_passwd);

	m_requestInfo = requestInfo;
	m_options = options;

	return(0);
}

//////////////////////////////////////////////////////////////////////
// ライン切り出し
//////////////////////////////////////////////////////////////////////
int CRequest::GetLine(CString &str, CString &line)
{
	int index = str.Find("\r\n");

	if(index == -1)
		return(0);
	
	//	切り出し
	line = str.Left(index);

	//	削除
	str = str.Mid(index + 2);
	return(1);
}

//////////////////////////////////////////////////////////////////////
// トークン切り出し
//////////////////////////////////////////////////////////////////////
int CRequest::GetToken(CString &str, CString &token, CString div)
{
	int tlen = div.GetLength();
	int index = str.Find(div);

	if(index == -1)
		return(0);
	
	//	切り出し
	token = str.Left(index);

	//	削除
	str = str.Mid(index + tlen);
	return(1);

}

