?? url.cpp.svn-base
字號:
/**
* url.cpp
*
* Copyright (C) 2008 David Andrs <pda@jasnapaka.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <afxwin.h>
#include "url.h"
#include "../../share/helpers.h"
#include "../../share/str.h"
#include "../../regex/regex.h"
#include "../debug/Logger.h"
#include "HTMLFile.h"
#include <wininet.h>
#if defined PRSSR_APP
// Taken from afxint.h
static BOOL AFXAPI _ParseURLWorker(LPCTSTR pstrURL,
LPURL_COMPONENTS lpComponents, DWORD& dwServiceType,
INTERNET_PORT& nPort, DWORD dwFlags)
{
// this function will return bogus stuff if lpComponents
// isn't set up to copy the components
ASSERT(lpComponents != NULL && pstrURL != NULL);
if (lpComponents == NULL || pstrURL == NULL)
return FALSE;
ASSERT(lpComponents->dwHostNameLength == 0 ||
lpComponents->lpszHostName != NULL);
ASSERT(lpComponents->dwUrlPathLength == 0 ||
lpComponents->lpszUrlPath != NULL);
ASSERT(lpComponents->dwUserNameLength == 0 ||
lpComponents->lpszUserName != NULL);
ASSERT(lpComponents->dwPasswordLength == 0 ||
lpComponents->lpszPassword != NULL);
ASSERT(AfxIsValidAddress(lpComponents, sizeof(URL_COMPONENTS), TRUE));
LPTSTR pstrCanonicalizedURL;
TCHAR szCanonicalizedURL[INTERNET_MAX_URL_LENGTH];
DWORD dwNeededLength = INTERNET_MAX_URL_LENGTH;
BOOL bRetVal;
BOOL bMustFree = FALSE;
DWORD dwCanonicalizeFlags = dwFlags &
(ICU_NO_ENCODE | ICU_DECODE | ICU_NO_META |
ICU_ENCODE_SPACES_ONLY | ICU_BROWSER_MODE);
DWORD dwCrackFlags = dwFlags & (ICU_ESCAPE | ICU_USERNAME);
bRetVal = InternetCanonicalizeUrl(pstrURL, szCanonicalizedURL,
&dwNeededLength, dwCanonicalizeFlags);
if (!bRetVal)
{
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
pstrCanonicalizedURL = new TCHAR[dwNeededLength];
bMustFree = TRUE;
bRetVal = InternetCanonicalizeUrl(pstrURL, pstrCanonicalizedURL,
&dwNeededLength, dwCanonicalizeFlags);
if (!bRetVal)
{
delete [] pstrCanonicalizedURL;
return FALSE;
}
}
else
pstrCanonicalizedURL = szCanonicalizedURL;
// now that it's safely canonicalized, crack it
bRetVal = InternetCrackUrl(pstrCanonicalizedURL, 0,
dwCrackFlags, lpComponents);
if (bMustFree)
delete [] pstrCanonicalizedURL;
// convert to MFC-style service ID
if (!bRetVal)
dwServiceType = INET_SERVICE_UNK;
else
{
nPort = lpComponents->nPort;
switch (lpComponents->nScheme)
{
case INTERNET_SCHEME_FTP:
dwServiceType = INET_SERVICE_FTP;
break;
case INTERNET_SCHEME_GOPHER:
dwServiceType = INET_SERVICE_GOPHER;
break;
case INTERNET_SCHEME_HTTP:
dwServiceType = INET_SERVICE_HTTP;
break;
case INTERNET_SCHEME_HTTPS:
dwServiceType = INET_SERVICE_HTTPS;
break;
case INTERNET_SCHEME_FILE:
dwServiceType = INET_SERVICE_FILE;
break;
case INTERNET_SCHEME_NEWS:
dwServiceType = INET_SERVICE_NNTP;
break;
case INTERNET_SCHEME_MAILTO:
dwServiceType = INET_SERVICE_MAILTO;
break;
default:
dwServiceType = INET_SERVICE_UNK;
}
}
return bRetVal;
}
BOOL AFXAPI ParseURL(LPCTSTR pstrURL, DWORD &dwServiceType, CString &strServer, CString &strObject, INTERNET_PORT &nPort) {
dwServiceType = INET_SERVICE_UNK;
ASSERT(pstrURL != NULL);
if (pstrURL == NULL)
return FALSE;
URL_COMPONENTS urlComponents;
memset(&urlComponents, 0, sizeof(URL_COMPONENTS));
urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
urlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
urlComponents.lpszHostName = strServer.GetBuffer(INTERNET_MAX_URL_LENGTH+1);
urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
urlComponents.lpszUrlPath = strObject.GetBuffer(INTERNET_MAX_URL_LENGTH+1);
BOOL bRetVal = _ParseURLWorker(pstrURL, &urlComponents, dwServiceType, nPort, ICU_BROWSER_MODE);
strServer.ReleaseBuffer();
strObject.ReleaseBuffer();
return bRetVal;
}
////
CString SanitizeUrl(const CString &url) {
int nPos = url.Find(_T("://"));
if (nPos != -1) {
int nEndPos = url.Find(_T("/"), nPos + 3);
CString sServer;
if (nEndPos != -1)
sServer = url.Mid(nPos + 3, nEndPos - nPos - 3);
else
sServer = url.Mid(nPos + 3);
sServer.MakeLower();
return url.Left(nPos + 3) + sServer + url.Mid(nEndPos);
}
else
return url;
}
//
//
//
CString GetURLFilePath(const CString &strObject) {
CString strObj;
int qmarkPos = strObject.Find('?');
if (qmarkPos != -1)
strObj = strObject.Left(qmarkPos);
else
strObj = strObject;
int slashPos = strObj.ReverseFind('/');
CString strPath = strObj.Left(slashPos + 1);
// if (strPath.GetLength() > 0 && strPath.GetAt(strPath.GetLength() - 1) != '/')
// strPath += '/';
return strPath;
}
CString GetUrlFileName(const CString &strUrl) {
CString strObj;
int qmarkPos = strUrl.Find('?');
if (qmarkPos != -1)
strObj = strUrl.Left(qmarkPos);
else
strObj = strUrl;
int slashPos = strObj.ReverseFind('/');
CString strPath = strObj.Mid(slashPos + 1);
return strPath;
}
/*BOOL ParseURL(const CString &url, CString &strServer, CString &strObject) {
LOG1(5, "ParseURL('%S')", url);
DWORD dwServiceType;
INTERNET_PORT nPort;
AfxParseURL(url, dwServiceType, strServer, strObject, nPort);
return TRUE;
}
*/
//
// Translates url to file path (<root>/<sever>/<object>)
//
CString UrlToFileName(const CString &url, BOOL addHTMLExt/* = FALSE*/) {
LOG1(5, "UrlToFileName('%S')", url);
if (url.Left(7).CompareNoCase(_T("file://")) == 0) {
CString fileName = url.Mid(7);
fileName.Replace('/', '\\');
return fileName;
}
DWORD serviceType;
INTERNET_PORT port;
CString strServer, strObject;
ParseURL(url, serviceType, strServer, strObject, port);
// remove #text
int hashPos = strObject.ReverseFind('#');
CString strHash;
if (hashPos != -1) {
strHash = strObject.Right(strObject.GetLength() - hashPos);
strObject = strObject.Left(hashPos);
}
CString strPath = GetURLFilePath(strObject);
CString strFileName = strObject.Right(strObject.GetLength() - strPath.GetLength());
// get params
int qmPos = strFileName.ReverseFind('?');
CString strPars;
if (qmPos != -1) {
strPars = strFileName.Right(strFileName.GetLength() - qmPos);
strFileName = strFileName.Left(qmPos);
}
int dotPos = strFileName.ReverseFind('.');
CString strExt;
if (dotPos != -1) {
strExt = strFileName.Right(strFileName.GetLength() - dotPos);
strFileName = strFileName.Left(dotPos);
}
if (strFileName.GetLength() == 0) {
strFileName = _T("index");
strExt = _T(".html");
}
// add html extension to files, which have none (to open in Pocket IE successfully)
if (addHTMLExt) {
if (strExt.CompareNoCase(_T(".html")) != 0 && strExt.CompareNoCase(_T(".htm")) != 0)
strExt = _T(".html"); // add html one
}
//
strPars.Replace('?', '_');
strPars.Replace(',', '_');
strPars.Remove('/');
strPars.Remove('\\');
// strFileName += strHash;
strPath.Replace('/', '\\');
CString strFileNamePath;
strFileNamePath.Format(_T("%s%s%s%s%s"), strServer, strPath, strFileName, strPars, strExt);
strFileNamePath.Remove('&');
strFileNamePath.Remove('=');
strFileNamePath.Remove('%');
strFileNamePath.Remove('\'');
strFileNamePath.Remove('"');
strFileNamePath.Remove(';');
strFileNamePath.Remove(':');
// truncate the file name to MAX_PATH (limit for filenames), because some URLs are longer than MAX_PATH
strFileNamePath = strFileNamePath.Left(MAX_PATH - 10);
return strFileNamePath;
}
CString MakeAbsoluteUrl(const CString &url, const CString &strServer, const CString &strPath) {
LOG1(5, "MakeAbsoluteUrl('%S')", url);
CString strAbsUrl;
if (url.Left(7).CompareNoCase(_T("http://")) == 0 ||
url.Left(8).CompareNoCase(_T("https://")) == 0 ||
url.Left(7).CompareNoCase(_T("file://")) == 0) {
// absolute link
strAbsUrl = url;
}
else {
// relative link
if (url.GetLength() > 0 && url.GetAt(0) == '/')
strAbsUrl.Format(_T("http://%s%s"), strServer, url);
else
strAbsUrl.Format(_T("http://%s%s%s"), strServer, strPath, url);
}
return strAbsUrl;
}
//
// Creates url for offline browsing in form (file://<url>)
// Keeps #part
//
CString MakeOfflineUrl(const CString &strRootDir, const CString &strFileName) {
LOG0(5, "MakeOfflineUrl()");
CString strOfflineUrl;
strOfflineUrl.Format(_T("file://localhost%s/%s"), strRootDir, strFileName);
strOfflineUrl.Replace('\\', '/');
return strOfflineUrl;
}
CString MakeOfflineUrl(const CString &strFileName) {
LOG0(5, "MakeOfflineUrl()");
CString strOfflineUrl;
strOfflineUrl.Format(_T("file://localhost%s"), strFileName);
strOfflineUrl.Replace('\\', '/');
return strOfflineUrl;
}
/*
//
// Create file url from object (#part is removed)
// For caching purposes
//
CString MakeOnlineFile(const CString &strObject, const CString &strServer, const CString &strActivePath) {
LOG0(5, "MakeOnlineFile()");
CString strAbsUrl;
if (strObject.Left(7).Compare(_T("file://")) == 0)
strAbsUrl = strObject;
else
strAbsUrl = MakeAbsoluteUrl(strObject, strServer, strActivePath);
CString strObjectFileName;
int hashPos = strAbsUrl.ReverseFind('#');
if (hashPos != -1)
strObjectFileName = strAbsUrl.Left(hashPos);
else
strObjectFileName = strAbsUrl;
return strObjectFileName;
}
*/
//
// Rewrite URL
//
CString RewriteUrl(const CString &sUrl, CArray<CRewriteRule *, CRewriteRule *> &rules) {
LOG1(5, "RewriteUrl('%S', )", sUrl);
CString newUrl = sUrl;
char *url = WCharToChar(sUrl, CP_ACP);
BOOL found = FALSE;
for (int i = 0; i < rules.GetSize() && !found; i++) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -