📄 http.cxx
字号:
#define DEFAULT_TELNET_PORT 23#define DEFAULT_GOPHER_PORT 70#define DEFAULT_HTTP_PORT 80#define DEFAULT_NNTP_PORT 119#define DEFAULT_WAIS_PORT 210#define DEFAULT_HTTPS_PORT 443#define DEFAULT_RTSP_PORT 554#define DEFAULT_RTSPU_PORT 554#define DEFAULT_PROSPERO_PORT 1525#define DEFAULT_H323_PORT 1720#define DEFAULT_H323RAS_PORT 1719#define DEFAULT_SIP_PORT 5060#define DEFINE_LEGACY_URL_SCHEME(schemeName, user, pass, host, def, defhost, query, params, frags, path, rel, port) \class PURLLegacyScheme_##schemeName : public PURLLegacyScheme \{ \ public: \ PURLLegacyScheme_##schemeName() \ : PURLLegacyScheme(#schemeName ) \ { \ hasUsername = user; \ hasPassword = pass; \ hasHostPort = host; \ defaultToUserIfNoAt = def; \ defaultHostToLocal = defhost; \ hasQuery = query; \ hasParameters = params; \ hasFragments = frags; \ hasPath = path; \ relativeImpliesScheme = rel; \ defaultPort = port; \ } \}; \ static PFactory<PURLScheme>::Worker<PURLLegacyScheme_##schemeName> schemeName##Factory(#schemeName, true); \DEFINE_LEGACY_URL_SCHEME(http, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, DEFAULT_HTTP_PORT )DEFINE_LEGACY_URL_SCHEME(file, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, 0)DEFINE_LEGACY_URL_SCHEME(https, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, DEFAULT_HTTPS_PORT)DEFINE_LEGACY_URL_SCHEME(gopher, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_GOPHER_PORT)DEFINE_LEGACY_URL_SCHEME(wais, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_WAIS_PORT)DEFINE_LEGACY_URL_SCHEME(nntp, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_NNTP_PORT)DEFINE_LEGACY_URL_SCHEME(prospero, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_PROSPERO_PORT)DEFINE_LEGACY_URL_SCHEME(rtsp, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_RTSP_PORT)DEFINE_LEGACY_URL_SCHEME(rtspu, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_RTSPU_PORT)DEFINE_LEGACY_URL_SCHEME(ftp, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, DEFAULT_FTP_PORT)DEFINE_LEGACY_URL_SCHEME(telnet, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, DEFAULT_TELNET_PORT)DEFINE_LEGACY_URL_SCHEME(mailto, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 0)DEFINE_LEGACY_URL_SCHEME(news, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 0)DEFINE_LEGACY_URL_SCHEME(h323, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, DEFAULT_H323_PORT)DEFINE_LEGACY_URL_SCHEME(sip, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, DEFAULT_SIP_PORT)DEFINE_LEGACY_URL_SCHEME(tel, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, 0)DEFINE_LEGACY_URL_SCHEME(fax, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, 0)DEFINE_LEGACY_URL_SCHEME(callto, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, 0)PINSTANTIATE_FACTORY(PURLScheme, PString)#define DEFAULT_SCHEME "http"#define FILE_SCHEME "file"//////////////////////////////////////////////////////////////////////////////// PURLPURL::PURL() : //scheme(SchemeTable[DEFAULT_SCHEME].name), scheme(DEFAULT_SCHEME), port(0), portSupplied (FALSE), relativePath(FALSE){}PURL::PURL(const char * str, const char * defaultScheme){ Parse(str, defaultScheme);}PURL::PURL(const PString & str, const char * defaultScheme){ Parse(str, defaultScheme);}PURL::PURL(const PFilePath & filePath) : //scheme(SchemeTable[FILE_SCHEME].name), scheme(FILE_SCHEME), port(0), portSupplied (FALSE), relativePath(FALSE){ PStringArray pathArray = filePath.GetDirectory().GetPath(); hostname = pathArray[0]; PINDEX i; for (i = 1; i < pathArray.GetSize(); i++) pathArray[i-1] = pathArray[i]; pathArray[i-1] = filePath.GetFileName(); SetPath(pathArray);}PObject::Comparison PURL::Compare(const PObject & obj) const{ PAssert(PIsDescendant(&obj, PURL), PInvalidCast); return urlString.Compare(((const PURL &)obj).urlString);}PINDEX PURL::HashFunction() const{ return urlString.HashFunction();}void PURL::PrintOn(ostream & stream) const{ stream << urlString;}void PURL::ReadFrom(istream & stream){ PString s; stream >> s; Parse(s);}PString PURL::TranslateString(const PString & str, TranslationType type){ PString xlat = str; 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); if (type == QueryTranslation) { PINDEX space = (PINDEX)-1; while ((space = xlat.Find(' ', space+1)) != P_MAX_INDEX) xlat[space] = '+'; } return xlat;}PString PURL::UntranslateString(const PString & str, TranslationType type){ PString xlat = str; xlat.MakeUnique(); PINDEX pos; if (type == PURL::QueryTranslation) { pos = (PINDEX)-1; while ((pos = xlat.Find('+', pos+1)) != P_MAX_INDEX) xlat[pos] = ' '; } pos = (PINDEX)-1; while ((pos = xlat.Find('%', pos+1)) != P_MAX_INDEX) { int digit1 = xlat[pos+1]; int digit2 = xlat[pos+2]; if (isxdigit(digit1) && isxdigit(digit2)) { xlat[pos] = (char)( (isdigit(digit2) ? (digit2-'0') : (toupper(digit2)-'A'+10)) + ((isdigit(digit1) ? (digit1-'0') : (toupper(digit1)-'A'+10)) << 4)); xlat.Delete(pos+1, 2); } } return xlat;}static void SplitVars(const PString & str, PStringToString & vars, char sep1, char sep2){ PINDEX sep1prev = 0; do { PINDEX sep1next = str.Find(sep1, sep1prev); if (sep1next == P_MAX_INDEX) sep1next--; // Implicit assumption string is not a couple of gigabytes long ... PINDEX sep2pos = str.Find(sep2, sep1prev); if (sep2pos > sep1next) sep2pos = sep1next; PCaselessString key = PURL::UntranslateString(str(sep1prev, sep2pos-1), PURL::QueryTranslation); if (!key) { PString data = PURL::UntranslateString(str(sep2pos+1, sep1next-1), PURL::QueryTranslation); if (vars.Contains(key)) vars.SetAt(key, vars[key] + ',' + data); else vars.SetAt(key, data); } sep1prev = sep1next+1; } while (sep1prev != P_MAX_INDEX);}void PURL::SplitQueryVars(const PString & queryStr, PStringToString & queryVars){ SplitVars(queryStr, queryVars, '&', '=');}BOOL PURL::InternalParse(const char * cstr, const char * defaultScheme){ urlString = cstr; scheme.MakeEmpty(); username.MakeEmpty(); password.MakeEmpty(); hostname.MakeEmpty(); port = 0; portSupplied = FALSE; relativePath = FALSE; pathStr.MakeEmpty(); path.SetSize(0); paramVars.RemoveAll(); fragment.MakeEmpty(); queryVars.RemoveAll(); // copy the string so we can take bits off it while (isspace(*cstr)) cstr++; PString url = cstr; // Character set as per RFC2396 PINDEX pos = 0; while (isalnum(url[pos]) || url[pos] == '+' || url[pos] == '-' || url[pos] == '.') pos++; PString schemeName; // get information which tells us how to parse URL for this // particular scheme PURLScheme * schemeInfo = NULL; // Determine if the URL has an explicit scheme if (url[pos] == ':') { // get the scheme information, or get the default scheme schemeInfo = PFactory<PURLScheme>::CreateInstance(url.Left(pos)); if (schemeInfo == NULL && defaultScheme == NULL) { PFactory<PURLScheme>::KeyList_T keyList = PFactory<PURLScheme>::GetKeyList(); if (keyList.size() != 0) schemeInfo = PFactory<PURLScheme>::CreateInstance(keyList[0]); } if (schemeInfo != NULL) url.Delete(0, pos+1); } // if we could not match a scheme, then use the specified default scheme if (schemeInfo == NULL && defaultScheme != NULL) schemeInfo = PFactory<PURLScheme>::CreateInstance(defaultScheme); // if that still fails, then use the global default scheme if (schemeInfo == NULL) schemeInfo = PFactory<PURLScheme>::CreateInstance(DEFAULT_SCHEME); // if that fails, then there is nowehere to go PAssert(schemeInfo != NULL, "Default scheme not available"); scheme = schemeInfo->GetName(); if (!schemeInfo->Parse(url, *this)) return FALSE; return !IsEmpty();}BOOL PURL::LegacyParse(const PString & _url, const PURLLegacyScheme * schemeInfo){ PString url = _url; PINDEX pos; // Super special case! if (scheme *= "callto") { // Actually not part of MS spec, but a lot of people put in the // into // the URL, so we take it out of it is there. if (url.GetLength() > 2 && url[0] == '/' && url[1] == '/') url.Delete(0, 2); // For some bizarre reason callto uses + instead of ; for paramters // We do a loop so that phone numbers of the form +61243654666 still work do { pos = url.Find('+'); } while (pos != P_MAX_INDEX && isdigit(url[pos+1])); if (pos != P_MAX_INDEX) { SplitVars(url(pos+1, P_MAX_INDEX), paramVars, '+', '='); url.Delete(pos, P_MAX_INDEX); } hostname = paramVars("gateway"); if (!hostname) username = UntranslateString(url, LoginTranslation); else { PCaselessString type = paramVars("type"); if (type == "directory") { pos = url.Find('/'); if (pos == P_MAX_INDEX) username = UntranslateString(url, LoginTranslation); else { hostname = UntranslateString(url.Left(pos), LoginTranslation); username = UntranslateString(url.Mid(pos+1), LoginTranslation); } } else { // Now look for an @ and split user and host pos = url.Find('@'); if (pos != P_MAX_INDEX) { username = UntranslateString(url.Left(pos), LoginTranslation); hostname = UntranslateString(url.Mid(pos+1), LoginTranslation); } else { if (type == "ip" || type == "host") hostname = UntranslateString(url, LoginTranslation); else username = UntranslateString(url, LoginTranslation); } } } // Allow for [ipv6] form pos = hostname.Find(']'); if (pos == P_MAX_INDEX) pos = 0; pos = hostname.Find(':', pos); if (pos != P_MAX_INDEX) { port = (WORD)hostname.Mid(pos+1).AsUnsigned(); portSupplied = TRUE; hostname.Delete(pos, P_MAX_INDEX); } password = paramVars("password"); return TRUE; } // if the URL should have leading slash, then remove it if it has one if (schemeInfo != NULL && schemeInfo->hasHostPort && schemeInfo->hasPath) { if (url.GetLength() > 2 && url[0] == '/' && url[1] == '/') url.Delete(0, 2); else relativePath = TRUE; } // parse user/password/host/port if (!relativePath && schemeInfo->hasHostPort) { PString endHostChars; if (schemeInfo->hasPath) endHostChars += '/'; if (schemeInfo->hasQuery) endHostChars += '?'; if (schemeInfo->hasParameters) endHostChars += ';'; if (schemeInfo->hasFragments) endHostChars += '#'; if (endHostChars.IsEmpty()) pos = P_MAX_INDEX; else pos = url.FindOneOf(endHostChars); PString uphp = url.Left(pos); if (pos != P_MAX_INDEX) url.Delete(0, pos); else url.MakeEmpty(); // if the URL is of type UserPasswordHostPort, then parse it if (schemeInfo->hasUsername) { // extract username and password PINDEX pos2 = uphp.Find('@'); PINDEX pos3 = P_MAX_INDEX; if (schemeInfo->hasPassword) pos3 = uphp.Find(':'); switch (pos2) { case 0 : uphp.Delete(0, 1); break; case P_MAX_INDEX : if (schemeInfo->defaultToUserIfNoAt) { if (pos3 == P_MAX_INDEX) username = UntranslateString(uphp, LoginTranslation); else { username = UntranslateString(uphp.Left(pos3), LoginTranslation); password = UntranslateString(uphp.Mid(pos3+1), LoginTranslation); } uphp.MakeEmpty(); } break; default : if (pos3 > pos2) username = UntranslateString(uphp.Left(pos2), LoginTranslation); else { username = UntranslateString(uphp.Left(pos3), LoginTranslation); password = UntranslateString(uphp(pos3+1, pos2-1), LoginTranslation); } uphp.Delete(0, pos2+1); } } // if the URL does not have a port, then this is the hostname if (schemeInfo->defaultPort == 0) hostname = UntranslateString(uphp, LoginTranslation); else { // determine if the URL has a port number // Allow for [ipv6] form pos = uphp.Find(']'); if (pos == P_MAX_INDEX) pos = 0; pos = uphp.Find(':', pos); if (pos == P_MAX_INDEX) hostname = UntranslateString(uphp, LoginTranslation); else { hostname = UntranslateString(uphp.Left(pos), LoginTranslation);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -