/*!
	UrlTools.cpp

	URL関係の処理
*/

#include "stdafx.h"
#include "UrlTools.h"
#include "UTF8StringTool.h"

//////////////////////////////////////////////////////////////////////
//	エンコード、デコード
//////////////////////////////////////////////////////////////////////
/*!
	URLデコードを行う
*/
void CUrlTools::UrlDecode(CUTF8String str, CBinaryData &decoded)
{
	//	空っぽに
	decoded.SetNoFreeEmpty(TRUE);
	decoded.ReSize(0);

	//	展開
	LPCU8STR	src = str.GetString();
	while(src[0] != 0)
	{
		//	"%"?
		if(src[0] =='%' && src[1] != 0 && src[2] != 0)
		{
			//	変換する
			char hex[] = { src[1], src[2], 0 };
			decoded.AppendByte((char)strtol(hex, NULL, 16));

			src+=2;
		}
		else if(src[0] == '+')
		{
			decoded.AppendByte(' ');
		}
		else
		{
			decoded.AppendByte(src[0]);
		}
		src++;
	}
}

/*!
	URLエンコードを行う
*/
CUTF8String CUrlTools::UrlEncode(CUTF8String str)
{
	CUTF8String		ret;
	LPCU8STR		src = str.GetString();

	//	展開
	while(*src != 0)
	{
		if(*src <= 0x20 || *src == '%' || *src == '#' ||  *src == '+' || *src >= 0x80)
		{
			//	危険な文字
			char	line[10];
			sprintf_s(line, 10, "%%%02x", *src);
			ret += (LPCU8STR)line;
		}
		else
		{
			ret += *src;
		}
		src++;
	}
	
	return(ret);
}

/*!
	UrlをUTF8へコンバートを試みる

	Urlデコードは行わないので、予めデコードしておく必要がある
	内部で一旦UTF16へ変換し、文字コードの正当性を検証している
	失敗すると、-1を返す
*/
int CUrlTools::UrlConvertToUTF8(CBinaryData decodedUrl, CUTF8String &utf8)
{
	int		len = decodedUrl.GetSize();
	decodedUrl.AppendByte(0);	//	文字列にする
	LPCSTR	unknown = decodedUrl.GetPtr();

	//	0を確認
	LPCSTR ptr = unknown;
	for(int i=0;i<len;i++)
		if(ptr[i] == 0)
			return(-1);		//	変換不能

	//	ASCII/UTF8?
	if(CUTF8StringTool::CheckAllAscii(decodedUrl.GetPtr(), len) || CUTF8StringTool::CheckIsUTF8(decodedUrl.GetPtr(), len))
	{
		//	一旦UTF16へ変換して戻す
		utf8 = _cnvU8(_cnvU16((LPCU8STR)unknown));
		if(utf8.IsEmpty())
			return(-1);		//	変換不能
		return(0);
	}

	//	一旦UTF16へ変換して戻す
	utf8 = _cnvU8((LPCSTR)unknown);
	if(utf8.IsEmpty())
		return(-1);		//	変換不能
	return(0);
}


//////////////////////////////////////////////////////////////////////
//	URL処理
//////////////////////////////////////////////////////////////////////
/*!
	オブジェクト切り出し
*/
CUTF8String CUrlTools::GetUrlObject(CUTF8String url)
{
	int index = url.Find(_U8("?"));
	if(index == -1)
		return(url);
	else
		return(url.Left(index));
}

/*!
	クエリ切り出し
*/
CUTF8String CUrlTools::GetQuery(CUTF8String url)
{
	int index = url.Find(_U8("?"));
	if(index == -1)
		return(_U8(""));
	else
		return(url.Mid(index + 1));
}


/*!
	URLを正規化
*/
CUTF8String CUrlTools::NormalizeUrl(CUTF8String url)
{
	//	必ず"/"で始まる
	if(url.Left(1) != _U8("/"))
		url = _U8("/") + url;

	//	安全の為、\:..を排除
	int count = url.GetLength();
	for(int i=0; i<count + 10; i++)
	{
		int rep = 0;

		rep += url.Replace(_U8("\\"),	_U8("/"));
		rep += url.Replace(_U8(":"),	_U8("/"));
		rep += url.Replace(_U8("/./"),	_U8("/"));			//	脆弱性：IPA#27428836 2006/06/30 Fix
		rep += url.Replace(_U8("/../"),	_U8("/"));
		rep += url.Replace(_U8("//"),	_U8("/"));
		if(rep == 0)
			break;
	}

	//	最終セキュリティテック
	if(url.Find(_U8("/../")) != -1)
		return _U8("");

	return url;
}
