std::string WideToUTF8(const WString &inWideString) { int len = 0; const wchar_t *chars = inWideString.c_str(); for(int i=0;i<inWideString.length();i++) { int c = chars[i]; if( c <= 0x7F ) len++; else if( c <= 0x7FF ) len+=2; else if( c <= 0xFFFF ) len+=3; else len+= 4; } std::string result; result.resize(len); unsigned char *data = (unsigned char *) &result[0]; for(int i=0;i<inWideString.length();i++) { int c = chars[i]; if( c <= 0x7F ) *data++ = c; else if( c <= 0x7FF ) { *data++ = 0xC0 | (c >> 6); *data++ = 0x80 | (c & 63); } else if( c <= 0xFFFF )
/////////////////////////////////////////////////////////////// // // DelTree // // // /////////////////////////////////////////////////////////////// bool SharedUtil::DelTree ( const SString& strPath, const SString& strInsideHere ) { // Safety: Make sure strPath is inside strInsideHere WString wstrPath = FromUTF8( strPath ); WString wstrInsideHere = FromUTF8( strInsideHere ); if ( !wstrPath.BeginsWithI( wstrInsideHere ) ) { assert ( 0 ); return false; } DWORD dwBufferSize = ( wstrPath.length() + 3 ) * sizeof( wchar_t ); wchar_t *szBuffer = static_cast < wchar_t* > ( alloca ( dwBufferSize ) ); memset ( szBuffer, 0, dwBufferSize ); wcsncpy ( szBuffer, wstrPath, wstrPath.length() ); SHFILEOPSTRUCTW sfos; sfos.hwnd = NULL; sfos.wFunc = FO_DELETE; sfos.pFrom = szBuffer; // Double NULL terminated sfos.pTo = NULL; sfos.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO; int status = SHFileOperationW(&sfos); return status == 0; }
// // Remove szOlds from the end of the string. // WString WString::TrimEnd ( const wchar_t* szOld ) const { const size_t uiOldLength = wcslen ( szOld ); WString strResult = *this; while ( strResult.length () >= uiOldLength && strResult.substr ( strResult.length () - uiOldLength ) == szOld ) strResult = strResult.substr ( 0, strResult.length () - uiOldLength ); return strResult; }
String md5(const WString& source) { MD5 md5; md5.update((UINT8*)source.c_str(), (UINT32)source.length() * sizeof(WString::value_type)); md5.finalize(); UINT8 digest[16]; md5.decdigest(digest, sizeof(digest)); char buf[33]; for (int i = 0; i < 16; i++) sprintf(buf + i * 2, "%02x", digest[i]); buf[32] = 0; return String(buf); }
// // Split into parts // void WString::Split ( const WString& strDelim, std::vector < WString >& outResult, unsigned int uiMaxAmount, unsigned int uiMinAmount ) const { outResult.clear (); unsigned long ulStartPoint = 0; while ( true ) { size_t ulPos = find ( strDelim, ulStartPoint ); if ( ulPos == npos || ( uiMaxAmount > 0 && uiMaxAmount <= outResult.size () + 1 ) ) { if ( ulStartPoint <= length () ) outResult.push_back ( substr ( ulStartPoint ) ); break; } outResult.push_back ( substr ( ulStartPoint, ulPos - ulStartPoint ) ); ulStartPoint = ulPos + strDelim.length (); } while ( outResult.size () < uiMinAmount ) outResult.push_back ( L"" ); }
//----------------------------------------------------------------------- void UnicodeFileSystemArchive::FileFinder::_run(const String& _dir, const WString& _wFullDir) { wchar_t wFindPattern[MAX_PATH]; wcscpy(wFindPattern, _wFullDir.c_str()); wcscpy(&wFindPattern[_wFullDir.length()], L"*"); long lHandle; struct _wfinddata_t wTagData; lHandle = _wfindfirst(wFindPattern, &wTagData); String tagDataName; String dir2; WString wFullDir2; while(lHandle != -1) { bool isSubDir = ((wTagData.attrib & _A_SUBDIR) != 0); bool isHidden = ((wTagData.attrib & _A_HIDDEN) != 0); if((!mIgnoreHidden || !isHidden) && !isReservedDir(wTagData.name) && ((isSubDir == mDirs) || (isSubDir && mRecursive))) { tagDataName = mArchive->toString(wTagData.name); if(isSubDir == mDirs && (mMask.empty() || StrUtil::match(tagDataName, mMask))) { if (mSimpleList) { mSimpleList->push_back(String()); String& back = mSimpleList->back(); back = _dir; back += tagDataName; } else if (mDetailList) { FileInfo fi; fi.archive = mArchive; fi.filename = _dir; fi.filename += tagDataName; fi.basename = tagDataName; fi.path = _dir; fi.compressedSize = wTagData.size; fi.uncompressedSize = wTagData.size; mDetailList->push_back(fi); } } if(isSubDir && mRecursive) { dir2 = _dir; dir2 += tagDataName; dir2 += '/'; wFullDir2 = _wFullDir; wFullDir2 += wTagData.name; wFullDir2 += '/'; _run(dir2, wFullDir2); } } if(_wfindnext( lHandle, &wTagData ) == -1) { _findclose(lHandle); lHandle = -1; } } }
bool WString::BeginsWithI ( const WString& strOther ) const { return _wcsicmp ( Left ( (int)strOther.length () ), strOther ) == 0; }
bool WString::BeginsWith ( const WString& strOther ) const { return Left ( (int)strOther.length () ) == strOther; }
bool WString::EndsWithI ( const WString& strOther ) const { return _wcsicmp ( Right ( (int)strOther.length () ), strOther ) == 0; }
bool WString::EndsWith ( const WString& strOther ) const { return Right ( (int)strOther.length () ) == strOther; }
// // Split in two // // eg "a.b.c.d.e" with strDelim == "." and iIndex == 1 gives "a" and "b.c.d.e" // "a.b.c.d.e" with strDelim == "." and iIndex == -2 gives "a.b.c" and "d.e" // bool WString::Split ( const WString& strDelim, WString* pstrLeft, WString* pstrRight, int iIndex ) const { // Check for self-overwrite if ( this == pstrLeft || this == pstrRight ) return WString ( *this ).Split ( strDelim, pstrLeft, pstrRight, iIndex ); assert ( iIndex ); bool bFromEnd = iIndex < 0; size_t ulPos; if ( !bFromEnd ) { ulPos = 0; for ( int i = 0 ; i < iIndex && ulPos != npos ; i++ ) { if ( i ) ulPos += strDelim.length (); if ( ulPos < length () ) { ulPos = find ( strDelim, ulPos ); } else { ulPos = npos; break; } } } else { ulPos = length (); for ( int i = 0 ; i < -iIndex && ulPos != npos ; i++ ) { if ( ulPos >= strDelim.length () ) { ulPos -= strDelim.length (); ulPos = rfind ( strDelim, ulPos ); } else { ulPos = npos; break; } } } if ( ulPos == npos ) { if ( pstrLeft ) *pstrLeft = bFromEnd ? L"" : c_str (); if ( pstrRight ) *pstrRight = bFromEnd ? c_str () : L""; return false; } if ( pstrLeft ) *pstrLeft = substr ( 0, ulPos ); if ( pstrRight ) *pstrRight = substr ( ulPos + strDelim.length (), length () - ( ulPos + strDelim.length () ) ); return true; }
int HttpConnection::request(InputStream& data, OutputStream& response, bool log_request) { int readBytes = 0; int totalBytesRead = 0; DWORD bytesWritten = 0; int ret = HTTP_STATUS_OK; WString headers; bool sendDataAtOnce = false; char *chunkToSend = NULL; int64_t contentLen = 0; INTERNET_BUFFERS BufferIn = {0}; DWORD errorCode = 0; char tmpbuff[1024]; #ifdef USE_ZLIB Bytef* cBuf = NULL; uLong cBufLen = 0; int64_t uncompressedContentLen = 0; #endif // Timeout to receive a rensponse from server (default = 30 sec). DWORD reqTimeoutMsec = requestTimeout * 1000; DWORD resTimeoutMsec = responseTimeout == 0 ? 30 * 1000 : responseTimeout * 1000; InternetSetOption(req, INTERNET_OPTION_RECEIVE_TIMEOUT, &reqTimeoutMsec, sizeof(DWORD)); InternetSetOption(req, INTERNET_OPTION_SEND_TIMEOUT, &resTimeoutMsec, sizeof(DWORD)); // InternetSetOption(req, SECURITY_FLAG_IGNORE_REVOCATION, NULL, 0); if (auth) { if (auth->getType() == HttpAuthentication::Basic) { StringBuffer authCred = auth->getAuthenticationHeaders(); StringBuffer authHeader; authHeader.sprintf("Basic %s", authCred.c_str()); setRequestHeader(HTTP_HEADER_AUTHORIZATION, authHeader); } else { LOG.error("%s: authentication type not supported [%d]", __FUNCTION__, auth->getType()); return StatusInternalError; } } // For user agent, content length and accept encoding, override property // values, even if set by the caller. setRequestHeader(HTTP_HEADER_USER_AGENT, userAgent); contentLen = data.getTotalSize() - data.getPosition(); #ifdef USE_ZLIB if (compression_enabled) { chunkToSend = new char [contentLen]; if (data.read((void *)chunkToSend, contentLen) != contentLen) { LOG.error("error reading data from input stream"); delete [] chunkToSend; return StatusInternalError; } sendDataAtOnce = true; cBufLen = contentLen; // DEFLATE (compress data) cBuf = new Bytef[contentLen]; // compress the source buffer into the destination buffer. int err = compress(cBuf, &cBufLen, (Bytef*)chunkToSend, contentLen); if (err != Z_OK) { LOG.error("%s: error compressing data buffer [%d]", __FUNCTION__, err); setError(ERR_HTTP_DEFLATE, "ZLIB: error occurred compressing data."); delete [] chunkToSend; delete [] cBuf; return StatusInternalError; } uncompressedContentLen = contentLen; contentLen = cBufLen; sprintf(tmpbuff, "%llu", contentLen); setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff); setRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, "deflate"); setRequestHeader(HTTP_HEADER_CONTENT_ENCODING, "deflate"); sprintf(tmpbuff, "%llu", uncompressedContentLen); setRequestHeader(HTTP_HEADER_UNCOMPRESSED_CONTENT_LENGTH, tmpbuff); } else { sprintf(tmpbuff, "%llu", contentLen); setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff); } #else sprintf(tmpbuff, "%llu", contentLen); setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff); #endif writeHttpHeaders(headers); // header in the log are written in writeHttpHeaders function // LOG.debug("Request header:\n\n%ls", headers.c_str()); // if the client allows to sync over https even if the server // has an invalid certificate, the flag is false. By default it is true //if (getSSLVerifyServer() == false) { /*DWORD extraSSLDwFlags = 0; DWORD dwBuffLen = sizeof(extraSSLDwFlags); extraSSLDwFlags |= SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_WRONG_USAGE | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS, &extraSSLDwFlags, sizeof (extraSSLDwFlags) ); */ if (url.isSecure()) { DWORD dwFlags, dwBuffLen = sizeof(dwFlags); InternetQueryOption (req, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen); if (getSSLVerifyServer() == false) { dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_WRONG_USAGE | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; } else { dwFlags = dwFlags| INTERNET_FLAG_SECURE; } InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags)); } bool retry = false; // give a chance to submit again if error is ERROR_INTERNET_SEC_CERT_REV_FAILED bool retryFlagRevocation = true; BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); // Must be set or error will occur BufferIn.Next = NULL; BufferIn.lpcszHeader = headers.c_str(); BufferIn.dwHeadersLength = headers.length(); BufferIn.dwHeadersTotal = 0; BufferIn.lpvBuffer = NULL; BufferIn.dwBufferLength = 0; BufferIn.dwBufferTotal = 0; //contentLen; BufferIn.dwOffsetLow = 0; BufferIn.dwOffsetHigh = 0; do { retry = false; if (!HttpSendRequestEx(req, &BufferIn, NULL, HSR_INITIATE, 0)) { DWORD err = GetLastError(); if (err == ERROR_INTERNET_SEC_CERT_REV_FAILED && retryFlagRevocation) { LOG.info("%s: error ERROR_INTERNET_SEC_CERT_REV_FAILED: retry once a time", __FUNCTION__); DWORD dwFlags, dwBuffLen = sizeof(dwFlags); InternetQueryOption (req, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen); dwFlags |= SECURITY_FLAG_IGNORE_REVOCATION; InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags)); retryFlagRevocation = false; retry = true; continue; } const char* msg = createHttpErrorMessage(err); LOG.error("HttpSendRequestEx failed: code %d: %s", err, msg); delete [] msg; return StatusNetworkError; } #ifdef USE_ZLIB if (compression_enabled) { if (sendData((const char *)cBuf, cBufLen) != 0) { delete [] cBuf; delete [] chunkToSend; return StatusWritingError; } delete [] cBuf; } #endif if (!sendDataAtOnce) { int64_t bufferSize = std::min(requestChunkSize, contentLen); chunkToSend = new char[bufferSize+1]; while ((readBytes = data.read((void *)chunkToSend, bufferSize))) { if (sendData(chunkToSend, readBytes) != 0) { delete [] chunkToSend; return StatusWritingError; } fireTransportEvent(readBytes, DATA_SENT); } } delete [] chunkToSend; if (data.error()) { LOG.error("[%s] Input stream read error: %d on %d bytes read", __FUNCTION__, data.getPosition(), data.getTotalSize()); return StatusStreamReadingError; } if (!HttpEndRequest(req, NULL, 0, 0)) { DWORD err = GetLastError(); const char* msg = createHttpErrorMessage(err); LOG.error("HttpEndRequest failed: code %d: %s", err, msg); delete [] msg; return StatusNetworkError; } readResponseHeaders(); ret = checkResponseStatus(); if (ret == ERROR_INTERNET_FORCE_RETRY) { retry = true; } } while (retry == true); if (isErrorStatus(ret)) { return ret; } StringBuffer nullval(NULL); if ((getRequestHeaders().get(HTTP_HEADER_RANGE) != nullval) && ret == 200) { // it means the client asks a partial response but the server doesn't support it. // the right answer from server is HTTP 206 LOG.info("%s: client asks a Range, but server responds 200 instead of 206 (Partial Content). Reset the outputstream and start from scratch.", __FUNCTION__); response.reset(); } if (readResponse(response) != 0) { return StatusReadingError; } return ret; }