📄 url.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player 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 Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA/* * @$Id: url.cpp,v 1.72.2.1 2007/02/20 16:25:35 jackjansen Exp $ */#ifndef AM_DBG#define AM_DBG if(0)#endif#include "ambulant/net/url.h"#include "ambulant/lib/logger.h"#include "ambulant/lib/string_util.h"#include "ambulant/lib/filesys.h"#include "ambulant/lib/textptr.h"#include <string>#if !defined(AMBULANT_NO_IOSTREAMS) && !defined(AMBULANT_NO_STRINGSTREAM)#include <sstream>#endifusing namespace ambulant;bool ambulant::net::url::s_strict = false;const std::string url_delim = ":/?#,";// Characters to be escaped in pathnames. Note that ~ and ? have special meanings in// http: urls, but not specifically in file: urls.const std::string file_url_escape_reqd = " <>{}|\\^[]`";const std::string file_url_escape = file_url_escape_reqd + "%";const std::string file_url_escape_frag = file_url_escape + "#";//// Helper routines to convert local file pathnames to url-style paths// and vice-versa//#ifdef AMBULANT_PLATFORM_WIN32#include "ambulant/lib/win32/win32_error.h"#include <wininet.h>static std::stringfilepath2urlpath(const std::string& fparg, bool handle_frag=false){ std::string filepath = fparg; size_t urlbufsize = filepath.size()*3+7; // Worst case: all characters escaped LPTSTR urlbuf = (LPTSTR)malloc(urlbufsize*sizeof(TCHAR)); DWORD urlbufsizearg = (DWORD)urlbufsize; assert(urlbuf); urlbuf[0] = 0; std::string fragment; if (handle_frag) { // Unfortunately passing ICU_BROWSER_MODE to ICU doesn't work:-( // Remove the fragment by hand, re-apply it later. size_t fragpos = filepath.find('#'); if (fragpos != std::string::npos) { fragment = filepath.substr(fragpos); filepath = filepath.substr(0, fragpos); } } if (!InternetCanonicalizeUrl(lib::textptr(filepath.c_str()), urlbuf, &urlbufsizearg, 0)) { DWORD dw = GetLastError(); lib::win32::win_report_error(filepath.c_str(), dw); urlbuf[0] = 0; } std::string rv = lib::textptr(urlbuf); // Work around stupid bug in InternetCanonicalizeURL: it forgets a slash. if (rv.substr(0, 7) == "file://" && rv[7] != '/') rv = "file:///" + rv.substr(7); // Now replace backslashes and turn everything into lower case std::string::iterator i; for(i=rv.begin(); i!=rv.end(); i++) { char c = *i; if (c == '\\') *i = '/'; else *i = tolower(c); } free(urlbuf); // Finally re-apply the fragment id, if there is one if (fragment != "") { rv = rv + fragment; } return rv;}static std::stringurlpath2filepath(const std::string& urlpath){ size_t filebufsize = urlpath.size()+1; LPTSTR filebuf = (LPTSTR)malloc(filebufsize*sizeof(TCHAR)); DWORD filebufsizearg = (DWORD)filebufsize; assert(filebuf); filebuf[0] = 0; lib::textptr tp(urlpath.c_str()); if (!InternetCanonicalizeUrl(tp, filebuf, &filebufsizearg, ICU_DECODE | ICU_NO_ENCODE)) { DWORD dw = GetLastError(); lib::win32::win_report_error(urlpath.c_str(), dw); filebuf[0] = 0; } std::string rv = lib::textptr(filebuf); // Work around stupid bug in InternetCanonicalizeURL: it forgets a slash. if (rv.substr(0, 8) == "file:///") rv = rv.substr(8); else if (rv[0] == '/' && rv[2] == ':') rv = rv.substr(1); // Finally replace slashes by backslashes std::string::iterator i; for(i=rv.begin(); i!=rv.end(); i++) { char c = *i; if (c == '/') *i = '\\'; } free(filebuf); return rv;}#else// Unix implementationstatic std::stringfilepath2urlpath(const std::string& filepath, bool handle_frag=false){ std::string::const_iterator i; std::string rv; const std::string *esc = &file_url_escape; if (handle_frag) esc = &file_url_escape_frag; for(i=filepath.begin(); i!=filepath.end(); i++) { char c = *i; if ( esc->find(c) != std::string::npos ) { char buf[4]; sprintf(buf, "%%%02.2x", (unsigned)c); rv += buf; } else { rv += c; } } return rv;}static std::stringurlpath2filepath(const std::string& urlpath){ std::string::const_iterator i; std::string rv; for(i=urlpath.begin(); i!=urlpath.end(); i++) { char c = *i; if ( c == '%' ) { char buf[3]; unsigned utfval; buf[0] = *++i; buf[1] = *++i; buf[2] = '\0'; if (sscanf(buf, "%x", &utfval) == 1) { rv += (char)utfval; } else { // Put the original string back. What else can we do... rv += '%'; rv += buf; } } else { rv += c; } } return rv;}#endif // AMBULANT_PLATFORM_WIN32/* static data and helper functions for URI %-en/decoding( RFC3986) */std::string hex_digits("0123456789ABCDEFabcdef");std::string gen_delims(":/?#[]@");std::string sub_delims("!$&'()*+,;=");std::string reserved(gen_delims+sub_delims);std::string unreserved(hex_digits+"GHIJKLMNOPQRSTUVWXYZghijklmnopqrstuvwxyz-._~");static boolis_hex (std::string& s) { for (size_t i = 0; i < s.size(); i++) { if (hex_digits.find(s[i]) == std::string::npos) return false; } return true;}static std::stringuint2hex (unsigned int val) { std::string rv = ""; unsigned int v = val; if (v == 0) rv += '0'; do { unsigned int pos = v&0xf; // get rightmost 4 bits rv.insert(0, hex_digits,pos,1); v >>= 4; } while (v != 0); if (rv.size() < 2) // ensure at least 2 chars rv.insert(0, "0"); return (rv);}static unsigned inthex2uint (std::string& s) { unsigned int rv = 0; for (size_t i = 0; i < s.size(); i++) { char c = s[i]; rv *= 16; unsigned int pos = (unsigned int) hex_digits.find(c); if (pos == std::string::npos) // not found, terminate break; if (pos >= 16) // lowercase a-f pos -= 6; rv += pos; // position in hex_digits is value of char } return (rv);}static boolis_reserved (unsigned int c) { const char cc = c; std::string s(1,cc); if (s.find_first_of(reserved) == std::string::npos) return false; return true;}static boolis_unreserved (unsigned int c) { const char cc = c; std::string s(1,cc); if (s.find_first_of(unreserved) == std::string::npos) return false; return true;}static std::stringuri2string(const std::string uri) { std::string rv = ""; std::string s = uri; size_t pos; while ((pos = s.substr().find("%")) != std::string::npos && (pos < s.size()-2)) { // pick next 2 characters std::string hex_chars = s.substr(pos+1,2); rv += s.substr(0,pos); if (is_hex(hex_chars)) rv += hex2uint(hex_chars); else { rv += "%"; // '%' not followed by 2 hex digits; pos -= 2; // continue next char after '%' } s = s.substr(pos+3); // skip "%xx" } rv += s; // concat tail return rv;}static std::stringstring2uri(const std::string str) { std::string rv = ""; for (size_t i = 0; i < str.size(); i++) { unsigned char c = str[i]; if (is_reserved(c) || is_unreserved(c)) { rv += c; } else if (c == '%') { if (i < str.size()-2) { // pick next 2 characters std::string ss = str.substr(i+1,2); if (is_hex(ss)) { unsigned int hc = hex2uint(ss); if (is_unreserved(hc)) { // convert unreserved %xx to char rv += hc; i +=2 ; continue; } } } rv += c; } else { // convert to '%' followed by 2 hex digits rv += '%'; rv += uint2hex(c); } } return rv;}// static //std::list< std::pair<std::string, net::url::HANDLER> > net::url::s_handlers;// workaround for g++ 2.95std::list< net::url_handler_pair* > s_handlers;// staticvoid net::url::init_statics() { // workaround for g++ 2.95 static url_handler_pair h1 = {"n://n:d/", &url::set_from_host_port_uri}; s_handlers.push_back(&h1); static url_handler_pair h1a = {"n://n:d", &url::set_from_host_port_uri}; s_handlers.push_back(&h1a); static url_handler_pair h1b = {"n://dn:d/", &url::set_from_numhost_port_uri}; s_handlers.push_back(&h1b); static url_handler_pair h1c = {"n://dn:d", &url::set_from_numhost_port_uri}; s_handlers.push_back(&h1c); static url_handler_pair h2 = {"n://n/", &url::set_from_host_uri}; s_handlers.push_back(&h2); static url_handler_pair h2a = {"n://n", &url::set_from_host_uri}; s_handlers.push_back(&h2a); static url_handler_pair h2b= {"n://dn/", &url::set_from_numhost_uri}; s_handlers.push_back(&h2b); static url_handler_pair h2c = {"n://dn", &url::set_from_numhost_uri}; s_handlers.push_back(&h2c); static url_handler_pair h3 = { "n:///", &url::set_from_localhost_file_uri}; s_handlers.push_back(&h3); static url_handler_pair h4a = { "n:,", &url::set_from_data_uri}; s_handlers.push_back(&h4a); static url_handler_pair h4b = { "n:n,", &url::set_from_data_uri}; s_handlers.push_back(&h4b); static url_handler_pair h4c = { "n:n/n,", &url::set_from_data_uri}; s_handlers.push_back(&h4c); static url_handler_pair h5 = {"/n", &url::set_from_absolute_path}; s_handlers.push_back(&h5); static url_handler_pair h6 = {"n:", &url::set_from_scheme}; s_handlers.push_back(&h6); static url_handler_pair h9 = {"", &url::set_from_relative_path}; s_handlers.push_back(&h9); /* typedef std::pair<std::string, HANDLER> pair; s_handlers.push_back(pair("n://n:n/",&url::set_from_host_port_uri)); s_handlers.push_back(pair("n://n/",&url::set_from_host_uri)); s_handlers.push_back(pair("n:///",&url::set_from_localhost_file_uri)); s_handlers.push_back(pair("/n",&url::set_from_unix_path)); s_handlers.push_back(pair("n:n",&url::set_from_windows_path)); s_handlers.push_back(pair("n:/n",&url::set_from_windows_path)); */ } // staticAMBULANTAPI net::url net::url::from_filename(const std::string& spec, bool handle_frag){ return net::url(filepath2urlpath(spec, handle_frag));}// staticAMBULANTAPI net::urlnet::url::from_filename(const char *spec, bool handle_frag){ return net::url(filepath2urlpath(spec, handle_frag));}// Private: check URL for character escapingvoid net::url::_checkurl() const{#if 0 // This is no longer valid, because escape-processing has been done on m_path if (m_path.find_first_of(file_url_escape_reqd) != std::string::npos) lib::logger::get_logger()->warn("%s: URL contains illegal characters", get_url().c_str());#endif}net::url::url() : m_absolute(true), m_port(0){} net::url::url(const string& spec) : m_port(0){ set_from_spec(spec);} net::url::url(const string& protocol, const string& host, const string& path) : m_protocol(protocol), m_host(host), m_port(0), m_path(path){ m_absolute = (m_protocol != ""); if (s_strict) _checkurl();}net::url::url(const string& protocol, const string& host, int port, const string& path)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -