2011. 4. 4. 18:17
Proxy 서버 구하기 (자동 구성 스크립트, pac)
2011. 4. 4. 18:17 in 프로그래밍/Let's Share it
proxy 환경에서,
MFC 함수 (CHttpFile)등 이외 curl library 같은 것을 사용하면, 시스템의 proxy 설정을 직접 해야 합니다.
즉, MFC 함수등에서는 따로 proxy등을 구하지 않아도 되지만,
그 위외의 경우에서는 직접 proxy를 구해 세팅을 해줘야 합니다.
그래서, 아래와 같은 함수를 공유합니다.
DWORD
GetProxyAddressFromSystem
IN LPCTSTR lpszUrl
IN LPCTSTR lpszAgentNameForQuery
OUT CStringArray& strArrayProxyAddr
IN LPCTSTR lpszAgentNameForQuery
OUT CStringArray& strArrayProxyAddr
lpszUrl : 구하려고 하는 Url. 예) http://www.naver.com (반드시 protocol이 필요함)
lpszAgentNameForQuery : Internet Session을 열때 필요한 Agent 이름. 예) MyApp.ver1
strArrayProxyAddr : 구해진 proxy 정보 list. 예) "111.222.111.222:1212", "222.111.222.111:2323", ...
리턴값 : ERROR_SUCCESS : 해당 url에 대해 proxy 서버가 필요함. strArrayProxyAddr 참고하기 바람.
이외는 오류값.
공유한 함수는 MFC 함수(CString)등을 사용하고 있는데, 좀더 참고하면 Plain C/C++ 등으로 수정 가능하리라 봅니다.
그리고, httpfile 함수군을 쓰니 (즉, #include <httpfile.h>)하니 오류가 생겨...
httpfile.dll을 동적으로 Load하는 방식을 사용했으니 참고 바랍니다.
(view plain 하시면 좀더 편하게 확인할 수 있습니다.)
(참고: WinHttpGetProxyForUrl를 사용하는데, 몇몇 옛날 OS(XPSP0, Win2K)에서는 지원여부가 명확하지 않습니다.)
#includeDWORD GetProxyAddressFromSystem(IN LPCTSTR lpszUrl, IN LPCTSTR lpszAgentNameForQuery, OUT CStringArray& strArrayProxyAddr) { #ifndef WINHTTP_AUTOPROXY_OPTIONS typedef struct { DWORD dwFlags; DWORD dwAutoDetectFlags; LPCWSTR lpszAutoConfigUrl; LPVOID lpvReserved; DWORD dwReserved; BOOL fAutoLogonIfChallenged; } WINHTTP_AUTOPROXY_OPTIONS; #endif #ifndef WINHTTP_PROXY_INFO typedef struct { DWORD dwAccessType; // see WINHTTP_ACCESS_* types below LPWSTR lpszProxy; // proxy server list LPWSTR lpszProxyBypass; // proxy bypass list } WINHTTP_PROXY_INFO, * LPWINHTTP_PROXY_INFO; #endif typedef BOOL (WINAPI *LPFN_WinHttpGetProxyForUrl)(HINTERNET hSession, LPCWSTR lpcwszUrl, WINHTTP_AUTOPROXY_OPTIONS* pAutoProxyOptions, WINHTTP_PROXY_INFO* pProxyInfo); typedef HINTERNET (WINAPI *LPFN_WinHttpOpen) (LPCWSTR pwszUserAgent, DWORD dwAccessType, LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass, DWORD dwFlags); typedef BOOL (WINAPI *LPFN_WinHttpCloseHandle) (HINTERNET hInternet); DWORD dwRtnValue = ERROR_SUCCESS; INT nFind = 0; INT nFind2 = 0; INTERNET_PER_CONN_OPTION_LIST List = {0,}; INTERNET_PER_CONN_OPTION Option[5] = {0,}; unsigned long nSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); HMODULE hWinHttp = NULL; LPFN_WinHttpGetProxyForUrl pfnWinHttpGetProxyForUrl = NULL; LPFN_WinHttpOpen pfnWinHttpOpen = NULL; LPFN_WinHttpCloseHandle pfnWinHttpCloseHandle = NULL; TCHAR szTmp[MAX_PATH] = {0,}; HINTERNET hInternet = NULL; WINHTTP_AUTOPROXY_OPTIONS stProxyOption = {0,}; WINHTTP_PROXY_INFO stProxyInfo = {0,}; CString strTmp; CString strDllPath; strArrayProxyAddr.RemoveAll(); if ((NULL == lpszUrl) || (NULL == lpszAgentNameForQuery)) { dwRtnValue = ERROR_INVALID_PARAMETER; ASSERT(FALSE); goto FINAL; } // 시스템 Proxy 설정부터 구하자. Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; Option[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; Option[2].dwOption = INTERNET_PER_CONN_FLAGS; Option[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; Option[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER; List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST); List.pszConnection = NULL; List.dwOptionCount = 5; List.dwOptionError = 0; List.pOptions = Option; if(!InternetQueryOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) { // getlasterror dwRtnValue = ::GetLastError(); if (ERROR_SUCCESS == dwRtnValue) { dwRtnValue = ERROR_INTERNAL_ERROR; } ASSERT(FALSE); goto FINAL; } if (((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL) && (NULL != Option[0].Value.pszValue)) { // 자동 구성 스크립스 사용 ::GetSystemDirectory(szTmp, MAX_PATH); if (TEXT('\0') == szTmp[0]) { dwRtnValue = ERROR_INTERNAL_ERROR; ASSERT(FALSE); goto FINAL; } strDllPath = szTmp; strDllPath.TrimRight(TEXT("\\")); strDllPath += TEXT("\\winhttp.dll"); hWinHttp = ::LoadLibrary(strDllPath); if (NULL == hWinHttp) { dwRtnValue = ::GetLastError(); ASSERT(FALSE); goto FINAL; } pfnWinHttpGetProxyForUrl = (LPFN_WinHttpGetProxyForUrl) ::GetProcAddress(hWinHttp, "WinHttpGetProxyForUrl"); pfnWinHttpOpen = (LPFN_WinHttpOpen) ::GetProcAddress(hWinHttp, "WinHttpOpen"); pfnWinHttpCloseHandle = (LPFN_WinHttpCloseHandle) ::GetProcAddress(hWinHttp, "WinHttpCloseHandle"); if ((NULL == pfnWinHttpGetProxyForUrl) || (NULL == pfnWinHttpOpen) || (NULL == pfnWinHttpCloseHandle)) { dwRtnValue = ERROR_MOD_NOT_FOUND; ASSERT(FALSE); goto FINAL; } hInternet = (*pfnWinHttpOpen)(lpszAgentNameForQuery, 0, // WINHTTP_ACCESS_TYPE_DEFAULT_PROXY NULL, // WINHTTP_NO_PROXY_NAME NULL, // WINHTTP_NO_PROXY_BYPASS 0); if (NULL == hInternet) { dwRtnValue = ::GetLastError(); if (ERROR_SUCCESS == dwRtnValue) { dwRtnValue = ERROR_INTERNAL_ERROR; } goto FINAL; } // 전달할 Option을 구한다. stProxyOption.dwFlags = 0x00000002; // WINHTTP_AUTOPROXY_CONFIG_URL stProxyOption.lpszAutoConfigUrl = Option[0].Value.pszValue; // 프록시 설정을 구한다. if (FALSE == (*pfnWinHttpGetProxyForUrl)(hInternet, lpszUrl, &stProxyOption, &stProxyInfo)) { dwRtnValue = ::GetLastError(); if (ERROR_SUCCESS == dwRtnValue) { dwRtnValue = ERROR_INTERNAL_ERROR; } goto FINAL; } if (NULL != stProxyInfo.lpszProxy) { // 여기까지 왔다면 성공 strTmp = stProxyInfo.lpszProxy; strTmp.TrimLeft(TEXT(" ;")); strTmp.TrimRight(TEXT(" ;")); for (;;) { nFind = strTmp.Find(TEXT(";"), nFind2); if (-1 == nFind) { strArrayProxyAddr.Add(strTmp.Mid(nFind2)); break; } strArrayProxyAddr.Add(strTmp.Mid(nFind2, nFind - nFind2)); nFind2 = nFind+1; } } else { dwRtnValue = ERROR_NOT_FOUND; goto FINAL; } } else if (((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) && (NULL != Option[4].Value.pszValue)) { // 사용자 LAN에 프록시 서버 사용 strArrayProxyAddr.Add(Option[4].Value.pszValue); } // 여기까지 왔다면 성공~!!! dwRtnValue = ERROR_SUCCESS; if (0 == strArrayProxyAddr.GetCount()) { // 발견되지 못했음 dwRtnValue = ERROR_NOT_FOUND; } FINAL: if(Option[0].Value.pszValue != NULL) { GlobalFree(Option[0].Value.pszValue); Option[0].Value.pszValue = NULL; } if(Option[3].Value.pszValue != NULL) { GlobalFree(Option[3].Value.pszValue); Option[3].Value.pszValue = NULL; } if(Option[4].Value.pszValue != NULL) { GlobalFree(Option[4].Value.pszValue); Option[4].Value.pszValue = NULL; } if ((NULL != hInternet) && (NULL != pfnWinHttpCloseHandle)) { (*pfnWinHttpCloseHandle)(hInternet); hInternet = NULL; } if (NULL != hWinHttp) { ::FreeLibrary(hWinHttp); hWinHttp = NULL; pfnWinHttpGetProxyForUrl = NULL; pfnWinHttpOpen = NULL; pfnWinHttpCloseHandle = NULL; } if ((NULL != stProxyInfo.lpszProxy)) { GlobalFree(stProxyInfo.lpszProxy); stProxyInfo.lpszProxy = NULL; } if ((NULL != stProxyInfo.lpszProxyBypass)) { GlobalFree(stProxyInfo.lpszProxyBypass); stProxyInfo.lpszProxyBypass = NULL; } return dwRtnValue; }
'프로그래밍 > Let's Share it' 카테고리의 다른 글
concat과 printf를 동시에 수행하는 함수 공유 (0) | 2011.10.14 |
---|---|
Window Event Log(윈도우 이벤트 로그) 읽기 (9) | 2011.07.20 |
Windows 확장자 등록 Helper 함수 공유 (0) | 2011.03.31 |
비동기(asynchronous) Http File Downloader 공유 (0) | 2011.01.27 |
sqlite unicode 지원(sqlite3_exec16)하기와 간략한 sqlite 예제 (0) | 2011.01.26 |