/*!
	更新履歴
	2005/05/21 ParseHeader,オプションヘッダの切り出し方を修正
*/

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

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

CRequest::~CRequest(void)
{
}


/*!
 *	ヘッダー解析
 *
 */
int CRequest::ParseHeader(CString &header, CWorkspaceAccess requestInfo)
{
	//	アクセスを設定
	m_requestInfo = requestInfo;

	//	各情報
	CString	line;
	CString	passwd;
	CString	user;
	CString	method;
	CString	uri;
	CString	uriObject;
	CString	version;
	CString	query;
	CString	queryDecoded;

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

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

	//	URIObject
	uriObject = CUrlUtility::GetUrlObject(uri);
	uriObject = CUrlUtility::DecodeUrl(uriObject);

	//	Query
	query = CUrlUtility::GetQuery(uri);
	queryDecoded = CUrlUtility::Decode(query);

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


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


	//	オプションヘッダー取得
	CWorkspaceAccess options = GetOptionAccess();
	CString	key;
	while(1)
	{
		if(GetLine(header,line)==0)
			break;

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

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

		//	利用禁止文字？
		if(key.Find(_T("::")) == -1)
			options.SetConfig(key,line);
	}


	//	ユーザーとパスワード（Basic認証の時だけ）
	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)
			{
				user = userpass.Left(index);
				passwd = userpass.Mid(index + 1);
			}
		}
	}


	//	環境へ設定
	m_requestInfo.SetConfig("Method",method);
	m_requestInfo.SetConfig("URL",uri);
	m_requestInfo.SetConfig("Object",uriObject);
	m_requestInfo.SetConfig("Version",version);
	m_requestInfo.SetConfig("Query",query);
	m_requestInfo.SetConfig("QueryDecoded",queryDecoded);
	m_requestInfo.SetConfig("User",user);
	m_requestInfo.SetConfig("Passwd",passwd);

	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);

}

