STDMETHODIMP CBHttpRequest::Open(BSTR strMethod, BSTR strUrl, VARIANT_BOOL bAsync, VARIANT varUser, VARIANT varPassword) { CUrl url; CStringA strObject; CStringA strUser; CStringA strPassword; Abort(); s_cs.Enter(); s_dwReqID ++; m_dwReqID = s_dwReqID; s_mapReq.SetAt(m_dwReqID, this); s_cs.Leave(); url.CrackUrl(CBStringA(strUrl)); m_bAsync = (bAsync != VARIANT_FALSE); strObject = url.GetUrlPath(); strObject.Append(url.GetExtraInfo()); if(varUser.vt != VT_ERROR) { HRESULT hr = varGetString(varUser, strUser); if(FAILED(hr))return hr; } if(varPassword.vt != VT_ERROR) { HRESULT hr = varGetString(varPassword, strPassword); if(FAILED(hr))return hr; } m_hConnection = InternetConnect(m_hSession, url.GetHostName(), url.GetPortNumber(), strUser.IsEmpty() ? NULL : (LPCSTR)strUser, strPassword.IsEmpty() ? NULL : (LPCSTR)strPassword, INTERNET_SERVICE_HTTP, 0, m_dwReqID); if(m_hConnection == NULL) return GetErrorResult(); m_hFile = HttpOpenRequest(m_hConnection, CBStringA(strMethod), strObject, NULL, NULL, NULL, m_dwFlags, m_dwReqID); if(m_hFile == NULL) return GetErrorResult(); m_eventComplete.Set(); return S_OK; }
HRESULT WINAPI MonitorSink::QueryIAuthenticate(void* pv, REFIID riid, LPVOID* ppv, DWORD dw) { * ppv = NULL; if ( pv && InlineIsEqualGUID(riid, IID_IAuthenticate) ) { MonitorSink * pThis = (MonitorSink *)pv; if ( pThis->m_pIEHostWindow && ! pThis->m_strURL.IsEmpty() && pThis->m_spTargetProtocol ) { do { CComPtr<IWinInetHttpInfo> spWinInetHttpInfo; if ( FAILED(pThis->m_spTargetProtocol->QueryInterface(&spWinInetHttpInfo)) ) break; if ( ! spWinInetHttpInfo ) break; CHAR szRawHeader[8192]; // IWinInetHttpInfo::QueryInfo() 返回的 Raw Header 不是 Unicode 的 DWORD dwBuffSize = ARRAYSIZE(szRawHeader); if ( FAILED(spWinInetHttpInfo->QueryInfo(HTTP_QUERY_RAW_HEADERS, szRawHeader, &dwBuffSize, 0, NULL)) ) break; CString strHeader; HttpRawHeader2CrLfHeader(szRawHeader, strHeader); static const WCHAR AUTH_HEAD [] = L"\r\nWWW-Authenticate:"; LPWSTR lpAuth = NULL; size_t nAuthLen = 0; if ( ! ExtractFieldValue( strHeader, AUTH_HEAD, & lpAuth, & nAuthLen ) ) break; if ( ! lpAuth ) break; CString strAuthScheme; CString strAuthRealm; // 可能有以下几种情况: // WWW-Authenticate: Basic realm="Secure Area" // WWW-Authenticate: Digest realm="*****@*****.**", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" // WWW-Authenticate: NTLM // WWW-Authenticate: NTLM <auth token> LPWSTR pPos = StrStrW(lpAuth, L" "); if ( pPos ) { * pPos = L'\0'; strAuthScheme = lpAuth; do { pPos = StrStrIW( pPos + 1, L"realm"); if ( ! pPos ) break; pPos = StrChrW( pPos + 5, L'='); if ( ! pPos ) break; pPos = StrChrW( pPos + 1, L'"'); if ( ! pPos ) break; LPWSTR lpRealm = pPos + 1; pPos = StrChrW( lpRealm, L'"'); if ( ! pPos ) break; * pPos = L'\0'; strAuthRealm = lpRealm; } while (false); } else { strAuthScheme = lpAuth; } VirtualFree( lpAuth, 0, MEM_RELEASE); // 由于 NPN_GetAuthenticationInfo 得不到 NTLM 的 domain,没办法做登录,只好不支持了 if (strAuthRealm == _T("NTLM")) return E_NOINTERFACE; CUrl url; if ( url.CrackUrl(pThis->m_strURL) ) { CW2A aScheme(url.GetSchemeName()); CW2A aHost(url.GetHostName()); int aPort = url.GetPortNumber(); char* username = NULL; char* password = NULL; uint32_t ulen = 0, plen = 0; char* szAuthScheme = CStringToUTF8String(strAuthScheme); char* szAuthRealm = CStringToUTF8String(strAuthRealm); NPError result = NPN_GetAuthenticationInfo(pThis->m_pIEHostWindow->m_pPlugin->m_pNPInstance, aScheme, aHost, aPort, szAuthScheme, szAuthRealm, &username, &ulen, &password, &plen ); delete[] szAuthScheme; delete[] szAuthRealm; if (result != NPERR_NO_ERROR) break; pThis->m_strUsername = username; pThis->m_strPassword = password; NPN_MemFree(username); NPN_MemFree(password); } * ppv = dynamic_cast<IAuthenticate *>(pThis); ((IUnknown*)*ppv)->AddRef(); return S_OK; } while (false); } } return E_NOINTERFACE; }
HRESULT FAsyncDownload::FHttpDownloadTP::ProcessDownload(FAsyncDownData *pData) { HRESULT hr = E_FAIL; FString ReqUrl = pData->m_pUrlInfo->m_DownloadUrl; UrlUnescapeInPlace(ReqUrl.GetBuffer(), 0); CUrl url; url.CrackUrl(ReqUrl); const tchar* pszUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"; FHInternet hIn = NULL; if (g_AppSettings.m_Proxy.GetLength() > 0) { hIn = InternetOpen(pszUserAgent, INTERNET_OPEN_TYPE_PROXY, g_AppSettings.m_Proxy, g_AppSettings.m_ProxyA, 0); } else { hIn = InternetOpen(pszUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); } if (NULL == hIn) return E_HTTP_NET_ERROR; FHInternet hCon = InternetConnect(hIn, url.GetHostName(), url.GetPortNumber(), url.GetUserName(), url.GetPassword(), INTERNET_SERVICE_HTTP, 0, 0); if (NULL == hCon) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: InternetConnect() failed: %d\n", GetLastError()); return E_HTTP_NET_ERROR; } ULONG ulRecvTimeout = 15000; InternetSetOption(hCon, INTERNET_OPTION_RECEIVE_TIMEOUT, &ulRecvTimeout, sizeof(ULONG)); FString StrRes = url.GetUrlPath(); StrRes+= url.GetExtraInfo(); FHInternet hReq = HttpOpenRequest(hCon, "GET", StrRes, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_DONT_CACHE, 0); if (NULL == hReq) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: HttpOpenRequest() failed: %d\n", GetLastError()); return E_HTTP_NET_ERROR; } size_type FileSize = 0; if (!(pData->m_pUrlInfo->m_dwDownloadFlags & HTTP_FLAG_NO_RESUME)) FileSize = GetFileSize(pData->m_pUrlInfo->m_DownloadFile); // See if file already exists on the disk. if (FileSize > 0) { FString StrRange; StrRange.Format("Range: bytes=%I64d-", FileSize); HttpAddRequestHeaders(hReq, StrRange, StrRange.GetLength(), HTTP_ADDREQ_FLAG_ADD_IF_NEW); } FString StrVersion; StrVersion.Format("LTV_VERSION: %s", g_AppSettings.m_AppVersion); HttpAddRequestHeaders(hReq, StrVersion, StrVersion.GetLength(), HTTP_ADDREQ_FLAG_ADD_IF_NEW); if (!HttpSendRequest(hReq, NULL, 0, NULL, 0)) { int err = GetLastError(); _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: HttpSendRequest() failed: %d (0x%x)\n", err, HRESULT_FROM_WIN32(err)); InternetCloseHandle(hCon); InternetCloseHandle(hIn); return E_HTTP_NET_ERROR; } const DWORD dwBufferSize = 8192; char pBuffer[dwBufferSize]; FHttpConnection FConn = hReq; DWORD dwStatusCode = FConn.GetStatusCode(); FString ReqContentType = pData->m_pUrlInfo->m_ContentType; pData->m_pUrlInfo->m_ContentType = FConn.GetHeader(HTTP_QUERY_CONTENT_TYPE); pData->m_pUrlInfo->m_dwStatusCode = dwStatusCode; if (!MatchContentType(ReqContentType, pData->m_pUrlInfo->m_ContentType)) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: Content type mismatch: %s/%s\n", ReqContentType, pData->m_pUrlInfo->m_ContentType); return E_NOINTERFACE; //E_NOINTERFACE = content type mismatch } if (dwStatusCode == 416 && FileSize > 0) { _DBGAlert("FAsyncDownload::FHttpDownloadTP::ProcessDownload: Server status code: %d. Download complete\n", dwStatusCode); return S_OK; } if (dwStatusCode < 200 || dwStatusCode > 206) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: Server status code: %d\n", dwStatusCode); if (dwStatusCode == 404) return E_HTTP_NOTFOUND; return E_HTTP_INVALID_STATUS; } CAtlFile OutFile; if (pData->m_pUrlInfo->m_dwDownloadFlags & HTTP_FLAG_NO_RESUME) DeleteFile(pData->m_pUrlInfo->m_DownloadFile); hr = OutFile.Create(pData->m_pUrlInfo->m_DownloadFile, GENERIC_WRITE, 0, OPEN_ALWAYS); if (FAILED(hr)) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: CreateFile failed: 0x%x, %d : %s\n", hr, GetLastError(), pData->m_pUrlInfo->m_DownloadFile); return E_HTTP_WRITE_FILE; } size_type llTotalRead = 0; size_type llSizeMax = 0; size_type ContentLen = FConn.GetContentLength(); pData->m_pUrlInfo->m_ContentLength = ContentLen; if (dwStatusCode == 206) { FString FStrRange = FConn.GetHeader(HTTP_QUERY_CONTENT_RANGE); if (FStrRange) { //Content-Range: bytes 21010-47021/47022 const char* pszBytes = strstr(FStrRange, "bytes "); if (pszBytes != NULL) { pszBytes+=sizeof("bytes"); LONGLONG llOffset = _strtoi64(pszBytes, NULL, 10); hr = OutFile.Seek(llOffset, FILE_BEGIN); llTotalRead = (size_type)llOffset; if (FAILED(hr)) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: Seek to position %d failed: 0x%x, %d\n", hr, GetLastError()); } const char* pszTotal = strchr(pszBytes, '/'); if (pszTotal != NULL) llSizeMax = _strtoi64(pszTotal + 1, NULL, 10); } } } else { if (ContentLen > 0 && ContentLen == FileSize) { OutFile.Close(); return S_OK; } } if (llSizeMax == 0) llSizeMax = ContentLen; pData->pBindStatusCallback.OnProgress((ULONG)llTotalRead, (ULONG)llSizeMax, BINDSTATUS_BEGINDOWNLOADDATA, L""); DWORD dwBytesRead = 0; for (;;) { if (!InternetReadFile(hReq, pBuffer, dwBufferSize, &dwBytesRead)) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: InternetReadFile() failed: %d\n", GetLastError()); OutFile.Close(); return E_HTTP_NET_ERROR; } if (dwBytesRead == 0) { hr = S_OK; break; } DWORD dwBytesWritten = 0; hr = OutFile.Write(pBuffer, dwBytesRead, &dwBytesWritten); if (FAILED(hr)) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: FileWrite failed: 0x%x, %d\n", hr, GetLastError()); OutFile.Close(); return E_HTTP_WRITE_FILE; } llTotalRead+=dwBytesRead; pData->pBindStatusCallback.OnProgress((ULONG)llTotalRead, llSizeMax > 0 ? (ULONG)llSizeMax : llTotalRead , BINDSTATUS_DOWNLOADINGDATA, L""); if (m_pThis->m_Stopping || pData->pBindStatusCallback.m_Abort) { _DBGAlert("**FAsyncDownload::FHttpDownloadTP::ProcessDownload: Download aborted\n", hr, GetLastError()); hr = E_ABORT; break; } } OutFile.Close(); return hr; }
int RunConverter( int argc, _TCHAR* * argv ) { #ifdef _DEBUG // sleep a bit so we can have time to attach a debugger Tell(_T("Sleeping for %d seconds in debug mode."), startupTimeout / 1000); Sleep(startupTimeout); #endif int ret = 0; wstring name; wstring title; HANDLE conversionHandle = NULL; po::options_description desc("Converts an MPEG-2 Program Stream to a DVR-MS, WMV, or WTV file."); po::positional_options_description pos; string input; string output; LONGLONG length; bool disableFileLogging; bool disableConsoleLogging; bool disableAllLogging; string interruptName; string interruptDirectory; string outputDirectory; string contentTitle; __int64 contentDuration = -1i64; desc.add_options() ("help,?", "Display help message.") ("input,i", po::value<string>(&input), "an MPEG2 input path. Can be a url.") ("output,o", po::value<string>(&output), "output path.<type>. Where <type> can be one of \"dvr-ms\", \"wmv\", or \"wtv\"") ("length,l", po::value<LONGLONG>(&length)->default_value(-1), "the length of the input content in bytes. Only required for a network path such as http." ) ("interrupt-name", po::value<string>(&interruptName), "the file name (without path or extension) of a file that will be created when conversion is to be interrupted.") ("interrupt-directory", po::value<string>(&interruptDirectory), "the path for this app to look for an interrupt file. An interrupt file is the interrupt_file name with a .interrupt extension. The file itself can be empty.") ("disable-file-logging", po::value<bool>(&disableFileLogging)->zero_tokens()->default_value(false), "indicates that logging to a file will be disabled.") ("disable-console-logging", po::value<bool>(&disableConsoleLogging)->zero_tokens()->default_value(false), "indicates that logging to the console will be disabled.") ("disable-all-logging", po::value<bool>(&disableAllLogging)->zero_tokens()->default_value(false), "indicates that all logging will be disabled.") ("output-directory,d", po::value<string>(&outputDirectory), "the directory for this app to place conversion output. Only valid if output_path is omitted.") ("content-title,t", po::value<string>(&contentTitle), "the Title that will be assigned to the output path.<type>.") ("version,v", po::value<string>()->zero_tokens(), "prints the version of this app.") //("content-duration,d", po::value<__int64>(&contentDuration)->default_value(-1i64), "the duration of the input content in seconds." ) ; pos.add("input", 1); pos.add("output", 1); pos.add("length", 1); vector<string> args; for (int i = 1; i < argc; i++) args.push_back(WStringToString(argv[i])); po::variables_map variables; try { po::basic_parsed_options<char> oo = po::command_line_parser(args). options(desc).positional(pos).run(); po::store(oo, variables); po::notify(variables); } catch (std::exception e) { Tell(_T("Invalid command line. Use --help to see options.")); return -1; } if (!variables.count("input")) { bool display = false; wstring message; if (variables.count("version")) { message = _T("Version: "); message += MPEG2DVRMS_VERSION; display = true; } if (variables.count("help")) { message = _T("eh... help message not available yet. Hope you have the source!"); display = true; } if (!display) message = _T("No input file was specified."); ret = 100; Tell(message); } else { try { ////////////////////////////////////////////////////////////////////////// // command-line option handling LONGLONG contentLength = -1; if (variables.count("length")) contentLength = length; if (variables.count("interrupt-name")) name = StringToWString(interruptName); else { name = NewGuid(); Tell(_T("Generated interrupt name is %s"), name.c_str()); } if (variables.count("interrupt-directory")) _conversionFileStoragePath = StringToWString(interruptDirectory); if (variables.count("content-title")) title = StringToWString(contentTitle); else title = _T(""); #pragma region input output file handling wstring defaultExtension; if (IsVista()) defaultExtension = _T(".dvr-ms"); else defaultExtension = _T(".wtv"); ATL_URL_SCHEME urlScheme; CUrl inputUrl; if (!inputUrl.CrackUrl(StringToWString(input).c_str())) urlScheme = ATL_URL_SCHEME_FILE; else urlScheme = inputUrl.GetScheme(); if (urlScheme == -1) urlScheme = ATL_URL_SCHEME_FILE; wstring inputPath = StringToWString(input); CPath outputPath; if (urlScheme == ATL_URL_SCHEME_FILE) { CPath input = inputPath.c_str(); if (input.IsFileSpec()) { TCHAR szCurrentDirectory[MAX_PATH]; if (!GetCurrentDirectory(MAX_PATH, szCurrentDirectory)) throw CarverLab::Exception(GetLastError()); wstring currentDirectory = (LPCTSTR)szCurrentDirectory; inputPath = currentDirectory + _T("\\") + inputPath.c_str(); input = inputPath.c_str(); } if (!input.FileExists()) throw CarverLab::Exception(_T("MPEG2 input path does not exist.")); if (!variables.count("output")) outputPath = inputPath.c_str(); else outputPath = StringToWString(output).c_str(); } else if (urlScheme == ATL_URL_SCHEME_HTTP || urlScheme == ATL_URL_SCHEME_HTTPS) { if (!variables.count("output")) { wstring thefullpath; CString envString; envString.GetEnvironmentVariable(_T("PUBLIC")); thefullpath = envString; thefullpath += _T("\\Videos\\mpeg2dvrms-output"); thefullpath += defaultExtension; outputPath = thefullpath.c_str(); } else outputPath = StringToWString(output).c_str(); } else throw CarverLab::Exception(_T("Only http or https URL schemes are supported.")); bool isUrl = urlScheme != ATL_URL_SCHEME_FILE; CPath inPath = inputPath.c_str(); if (outputPath.GetExtension().MakeLower() == inPath.GetExtension().MakeLower()) outputPath.RenameExtension(defaultExtension.c_str()); if (outputPath.GetExtension().MakeLower() == _T(".dvrms")) { outputPath.RemoveExtension(); outputPath.AddExtension(_T(".dvr-ms")); } #pragma endregion input output file handling ////////////////////////////////////////////////////////////////////////// conversionHandle = CreateConversion(false, CComBSTR(name.c_str())); if (!conversionHandle) throw CarverLab::Exception(); SetConsoleTitle(outputPath); Tell(_T("Press ENTER to interrupt and exit.")); _done = false; HANDLE stdinput = GetStdHandle(STD_INPUT_HANDLE); std::auto_ptr<InternalThreadData> threadData(new InternalThreadData); threadData->activityCallback = ActivityCallback; threadData->contentLength = contentLength; threadData->conversionHandle = conversionHandle; threadData->inputPath = inPath; threadData->isUrl = isUrl; threadData->outputPath = outputPath; threadData->threadData = NULL; threadData->userData = NULL; threadData->contentTitle = StringToWString(contentTitle); threadData->contentDuration = contentDuration; _lastConvertedFilePath = outputPath; HANDLE thread = CreateThread(NULL, 0, BeginConversion, threadData.get(), 0, NULL); if (thread == NULL) throw CarverLab::Exception(); bool shuttingDown = false; bool interruptSuccessful = false; // will be true if the conversion is inactive after InterruptConversion is called while (!_done) { if (!shuttingDown && ((_kbhit() && _getch() == 13) || InterruptNow(name.c_str()))) { shuttingDown = true; interruptSuccessful = InterruptConversion(conversionHandle, 30000); // will wait 30 seconds for the conversion to die } Sleep(10); } if (!interruptSuccessful) { // TODO: will need to kill this puppy in an unnice way... awwww Tell(_T("InterruptConversion was unsusccessful.")); } // TODO: INFINITE? um... nope. this will need an intervention WaitForSingleObject(thread, INFINITE); CloseHandle(thread); } catch (CarverLab::Exception exception) { Tell(_T("*** Error: %s"), exception.GetErrorString()); Tell(_T("Exiting...")); ret = exception.GetHRESULT(); } catch (...) { DWORD errorCode = GetLastError(); wstring error = Exception::GetLastErrorString(errorCode); Tell(_T("*** Unhandled Exception: %s"), error.c_str()); Tell(_T("Exiting...")); ret = errorCode; } if (conversionHandle != NULL) CloseConversion(conversionHandle); } #ifdef _DEBUG // sleep a bit so we can see any errors Tell(_T("Sleeping for %d seconds in debug mode."), sleepTimeout / 1000); Sleep(sleepTimeout); #endif return ret; }