#include "StdAfx.h"
#include "HTTPHeaderParser.h"
#include "TextTools.h"
#include "UrlUtility.h"

/*!
	リクエストヘッダーの解析を行う
*/
int CHTTPHeaderParser::ParseRequestHeader(CString &header, CContextRequestInfo requestInfo)
{
	CString	line;
	CString	method;
	CString	url;
	CString	object;
	CString	query;
	CString	queryDecoded;
	CString	version;
	CString	user;
	CString	passwd;

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

	//	URL
	if(CTextTools::GetToken(line, url, " ")==0)
		return(-1);

	//	URIObject
	object = CUrlUtility::GetUrlObject(url);
	object = CUrlUtility::DecodeUrl(object);

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

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

	//	設定
	requestInfo.Clear();
	requestInfo.SetMethod(method);
	requestInfo.SetURL(url);
	requestInfo.SetObject(object);
	requestInfo.SetQuery(query);
	requestInfo.SetQueryDecoded(queryDecoded);
	requestInfo.SetVersion(version);


	//	オプションヘッダー取得
	CContextRequestOption options = requestInfo.GetRequestOption();
	CString	key;
	while(1)
	{
		if(CTextTools::GetLine(header,line)==0)
			break;

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

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

		options.SetKeyStr(key,line);
	}
	return(0);
}


/*!
	レスポンスヘッダの生成を行う
*/
CString CHTTPHeaderParser::GetResponseHeader(CContextResponseInfo responseInfo)
{
	CContextResponseOption responseOptions = responseInfo.GetResponseOption();

	//	レスポンスライン
	CString	header,line;
	line.Format("HTTP/1.1 %s\r\n", GetResponseText(responseInfo.GetResponseCode(), responseInfo.GetResponseText()));
	header += line;

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

	//	CGI用ヘッダ
	header += responseInfo.GetCGIHeader();
	header.TrimRight();
	header += "\r\n\r\n";

	return(header);
}


/*!
	レスポンステキスト取得
*/
CString CHTTPHeaderParser::GetResponseText(int code, CString responseText)
{
	//	responseTextが設定されている？
	if(!responseText.IsEmpty())
	{
		responseText.Replace("\r", "");
		responseText.Replace("\n", "");

		//	数字指定？
		if(responseText.GetLength() > 4 && responseText[3] == ' ' && atoi(responseText.Left(3)) >= 100)
			return(responseText);
		else
			return(CTextTools::GetFormat("%d %s",code,responseText));
	}

	//	設定
	switch(code)
	{
		//	成功
		case	100:
			return("100 Continue");
		case	101:
			return("101 Switching Protocols");
		case	200:
			return("200 OK");
		case	201:
			return("201 Created");
		case	202:
			return("202 Accepted");
		case	203:
			return("203 Non-Authoritative Information");
		case	204:
			return("204 No Content");
		case	205:
			return("205 Reset Content");
		case	206:
			return("206 Partial Content");
		case	207:
			return("207 Multi-Status");

		//	エラー（30xは自動に処理される）
		case	300:
			return("300 Multiple Choices");
		case	301:
			return("301 Moved Permanently");
		case	302:
			return("302 Found");
		case	303:
			return("303 See Other");
		case	304:
			return("304 Not Modified");
		case	305:
			return("305 Use Proxy");
		case	306:
			return("306 (Unused)");
		case	307:
			return("307 Temporary Redirect");


		case	400:
			return("400 Bad Request");
		case	401:
			return("401 Unauthorized");
		case	402:
			return("402 Payment Required");
		case	403:
			return("403 Forbidden");
		case	404:
			return("404 Not Found");
		case	405:
			return("405 Method Not Allowed");
		case	406:
			return("406 Not Acceptable");
		case	407:
			return("407 Proxy Authentication Required");
		case	408:
			return("408 Request Timeout");
		case	409:
			return("409 Conflict");
		case	410:
			return("410 Gone");
		case	411:
			return("411 Length Required");
		case	412:
			return("412 Precondition Failed");
		case	413:
			return("413 Request Entity Too Large");
		case	414:
			return("414 Request-URI Too Long");
		case	415:
			return("415 Unsupported Media Type");
		case	416:
			return("416 Requested Range Not Satisfiable");


		case	500:
			return("500 Internal Server Error");
		case	501:
			return("501 Not Implemented");
		case	502:
			return("502 Bad Gateway");
		case	503:
			return("503 Service Unavailable");
		case	504:
			return("504 Gateway Timeout");
		case	505:
			return("505 HTTP Version Not Supported");
	}

	CString	unknown;
	unknown.Format("%d UNKNOWN",code);
	return(unknown);
}
