📄 http.cxx
字号:
Parse(s);
}
PString PURL::TranslateString(const PString & str, TranslationType type)
{
PString xlat = str;
if (type == QueryTranslation) {
PINDEX space = (PINDEX)-1;
while ((space = xlat.Find(' ', space+1)) != P_MAX_INDEX)
xlat[space] = '+';
}
PString safeChars = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789$-_.+!*'(),";
switch (type) {
case LoginTranslation :
safeChars += ";?&=";
break;
case PathTranslation :
safeChars += ":@&=";
break;
case QueryTranslation :
safeChars += ":@";
}
PINDEX pos = (PINDEX)-1;
while ((pos += 1+strspn(&xlat[pos+1], safeChars)) < xlat.GetLength())
xlat.Splice(psprintf("%%%02X", (BYTE)xlat[pos]), pos, 1);
return xlat;
}
static void UnmangleString(PString & str, PURL::TranslationType type)
{
PINDEX pos;
if (type == PURL::QueryTranslation) {
pos = (PINDEX)-1;
while ((pos = str.Find('+', pos+1)) != P_MAX_INDEX)
str[pos] = ' ';
}
pos = (PINDEX)-1;
while ((pos = str.Find('%', pos+1)) != P_MAX_INDEX) {
int digit1 = str[pos+1];
int digit2 = str[pos+2];
if (isxdigit(digit1) && isxdigit(digit2)) {
str[pos] = (char)(
(isdigit(digit2) ? (digit2-'0') : (toupper(digit2)-'A'+10)) +
((isdigit(digit1) ? (digit1-'0') : (toupper(digit1)-'A'+10)) << 4));
str.Delete(pos+1, 2);
}
}
}
void PURL::SplitQueryVars(const PString & queryStr, PStringToString & queryVars)
{
PStringArray tokens = queryStr.Tokenise("&=", TRUE);
for (PINDEX i = 0; i < tokens.GetSize(); i += 2) {
PCaselessString key = tokens[i];
UnmangleString(key, QueryTranslation);
PString data = tokens[i+1];
UnmangleString(data, QueryTranslation);
if (queryVars.Contains(key))
queryVars.SetAt(key, queryVars[key] + ',' + data);
else
queryVars.SetAt(key, data);
}
}
void PURL::Parse(const char * cstr)
{
hostname = PCaselessString();
pathStr = username = password = parameters = fragment = queryStr = PString();
path.SetSize(0);
queryVars.RemoveAll();
port = 0;
// copy the string so we can take bits off it
while (isspace(*cstr))
cstr++;
PString url = cstr;
PINDEX pos;
static const PString reservedChars = "=;/#?";
// determine if the URL has a scheme
scheme = "";
if (isalpha(url[0])) {
for (pos = 0; url[pos] != '\0' &&
reservedChars.Find(url[pos]) == P_MAX_INDEX; pos++) {
if (url[pos] == ':') {
scheme = url.Left(pos);
url.Delete(0, pos+1);
break;
}
}
}
// if there is no scheme, then default to http for the local
// on the default port
if (scheme.IsEmpty()) {
scheme = "http";
if (url.GetLength() > 2 && url[0] == '/' && url[1] == '/')
url.Delete(0, 2);
} else {
// get information which tells us how to parse URL for this
// particular scheme
const schemeStruct & schemeInfo = GetSchemeInfo(scheme);
// if the URL should have leading slash, then remove it if it has one
if (schemeInfo.hasDoubleSlash &&
url.GetLength() > 2 && url[0] == '/' && url[1] == '/')
url.Delete(0, 2);
// if the rest of the URL isn't a path, then we are finished!
if (schemeInfo.type == Other) {
pathStr = url;
return;
}
// parse user/password/host/port
if (schemeInfo.type == HostPort ||
schemeInfo.type == UserPasswordHostPort ||
schemeInfo.type == HostOnly) {
pos = url.Find('/');
PString uphp = url.Left(pos);
if (pos != P_MAX_INDEX)
url.Delete(0, pos);
else
url = PString();
// if the URL is of type HostOnly, then this is the hostname
if (schemeInfo.type == HostOnly) {
hostname = uphp;
UnmangleString(hostname, LoginTranslation);
}
// if the URL is of type UserPasswordHostPort, then parse it
if (schemeInfo.type == UserPasswordHostPort) {
// extract username and password
PINDEX pos2 = uphp.Find('@');
if (pos2 != P_MAX_INDEX && pos2 > 0) {
PINDEX pos3 = uphp.Find(":");
// if no password...
if (pos3 > pos2)
username = uphp(0, pos2-1);
else {
username = uphp(0, pos3-1);
password = uphp(pos3+1, pos2-1);
UnmangleString(password, LoginTranslation);
}
UnmangleString(username, LoginTranslation);
uphp.Delete(0, pos2+1);
}
}
// determine if the URL has a port number
if (schemeInfo.type == HostPort ||
schemeInfo.type == UserPasswordHostPort) {
pos = uphp.Find(":");
if (pos == P_MAX_INDEX) {
hostname = uphp;
port = schemeInfo.defaultPort;
} else {
hostname = uphp.Left(pos);
port = (WORD)uphp(pos+1, P_MAX_INDEX).AsInteger();
}
UnmangleString(hostname, LoginTranslation);
if (hostname.IsEmpty())
hostname = PIPSocket::GetHostName();
}
}
}
// chop off any trailing fragment
pos = url.Find('#');
if (pos != P_MAX_INDEX && pos > 0) {
fragment = url(pos+1, P_MAX_INDEX);
UnmangleString(fragment, PathTranslation);
url.Delete(pos, P_MAX_INDEX);
}
// chop off any trailing query
pos = url.Find('?');
if (pos != P_MAX_INDEX && pos > 0) {
queryStr = url(pos+1, P_MAX_INDEX);
url.Delete(pos, P_MAX_INDEX);
SplitQueryVars(queryStr, queryVars);
}
// chop off any trailing parameters
pos = url.Find(';');
if (pos != P_MAX_INDEX && pos > 0) {
parameters = url(pos+1, P_MAX_INDEX);
UnmangleString(parameters, PathTranslation);
url.Delete(pos, P_MAX_INDEX);
}
// the hierarchy is what is left
pathStr = url;
path = url.Tokenise("/", TRUE);
if (path.GetSize() > 0 && path[0].IsEmpty())
path.RemoveAt(0);
for (pos = 0; pos < path.GetSize(); pos++) {
UnmangleString(path[pos], PathTranslation);
if (pos > 0 && path[pos] == ".." && path[pos-1] != "..") {
path.RemoveAt(pos--);
path.RemoveAt(pos--);
}
}
}
PString PURL::AsString(UrlFormat fmt) const
{
PStringStream str;
if (fmt == FullURL || fmt == HostPortOnly) {
// if the scheme is empty, assume http
if (!scheme) {
str << scheme << ':';
const schemeStruct & schemeInfo = GetSchemeInfo(scheme);
if (schemeInfo.hasDoubleSlash)
str << "//";
if (schemeInfo.type == Other)
str << pathStr;
else {
if (schemeInfo.type == HostOnly)
str << hostname;
if (schemeInfo.type == UserPasswordHostPort) {
if (!username || !password)
str << TranslateString(username, LoginTranslation)
<< ':'
<< TranslateString(password, LoginTranslation)
<< '@';
}
if (schemeInfo.type == HostPort || schemeInfo.type == UserPasswordHostPort) {
if (hostname.IsEmpty())
str = PString();
else {
str << hostname;
if (port != schemeInfo.defaultPort)
str << ':' << port;
}
}
}
}
if (fmt == HostPortOnly)
return str;
}
PINDEX count = path.GetSize();
if (count > 0) {
str << '/';
for (PINDEX i = 0; i < count; i++) {
str << TranslateString(path[i], PathTranslation);
if (i < count-1)
str << '/';
}
}
if (fmt == FullURL || fmt == URIOnly) {
if (!parameters)
str << ";" << TranslateString(parameters, PathTranslation);
if (!queryStr)
str << "?" << queryStr;
if (!fragment)
str << "#" << TranslateString(fragment, PathTranslation);
}
return str;
}
BOOL PURL::OpenBrowser(const PString & url)
{
#ifdef WIN32
if ((int)ShellExecute(NULL, "open", url, NULL, NULL, 0) > 32)
return TRUE;
MessageBox(NULL, "Unable to open page"&url, PProcess::Current().GetName(), MB_TASKMODAL);
#endif
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// PHTTP
static char const * const HTTPCommands[PHTTP::NumCommands] = {
// HTTP 1.0 commands
"GET", "HEAD", "POST",
// HTTP 1.1 commands
"PUT", "DELETE", "TRACE", "OPTIONS",
// HTTPS command
"CONNECT"
};
const PCaselessString PHTTP::AllowTag = "Allow";
const PCaselessString PHTTP::AuthorizationTag = "Authorization";
const PCaselessString PHTTP::ContentEncodingTag = "Content-Encoding";
const PCaselessString PHTTP::ContentLengthTag = "Content-Length";
const PCaselessString PHTTP::ContentTypeTag = "Content-Type";
const PCaselessString PHTTP::DateTag = "Date";
const PCaselessString PHTTP::ExpiresTag = "Expires";
const PCaselessString PHTTP::FromTag = "From";
const PCaselessString PHTTP::IfModifiedSinceTag = "If-Modified-Since";
const PCaselessString PHTTP::LastModifiedTag = "Last-Modified";
const PCaselessString PHTTP::LocationTag = "Location";
const PCaselessString PHTTP::PragmaTag = "Pragma";
const PCaselessString PHTTP::PragmaNoCacheTag = "no-cache";
const PCaselessString PHTTP::RefererTag = "Referer";
const PCaselessString PHTTP::ServerTag = "Server";
const PCaselessString PHTTP::UserAgentTag = "User-Agent";
const PCaselessString PHTTP::WWWAuthenticateTag = "WWW-Authenticate";
const PCaselessString PHTTP::MIMEVersionTag = "MIME-Version";
const PCaselessString PHTTP::ConnectionTag = "Connection";
const PCaselessString PHTTP::KeepAliveTag = "Keep-Alive";
const PCaselessString PHTTP::ProxyConnectionTag = "Proxy-Connection";
const PCaselessString PHTTP::ProxyAuthorizationTag = "Proxy-Authorization";
const PCaselessString PHTTP::ProxyAuthenticateTag = "Proxy-Authenticate";
const PCaselessString PHTTP::ForwardedTag = "Forwarded";
const PCaselessString PHTTP::SetCookieTag = "Set-Cookie";
const PCaselessString PHTTP::CookieTag = "Cookie";
PHTTP::PHTTP()
: PInternetProtocol("www 80", NumCommands, HTTPCommands)
{
}
PINDEX PHTTP::ParseResponse(const PString & line)
{
PINDEX endVer = line.Find(' ');
if (endVer == P_MAX_INDEX) {
lastResponseInfo = "Bad response";
lastResponseCode = PHTTP::InternalServerError;
return 0;
}
lastResponseInfo = line.Left(endVer);
PINDEX endCode = line.Find(' ', endVer+1);
lastResponseCode = line(endVer+1,endCode-1).AsInteger();
if (lastResponseCode == 0)
lastResponseCode = PHTTP::InternalServerError;
lastResponseInfo &= line.Mid(endCode);
return 0;
}
// End Of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -