POCO C++库学习和分析 -- URI
POCO C++库学习和分析 -- URI (Uniform Resource Identifiers)
1. 概述
URI(RFC 3986)意为统一资源标记,通常被用来标志web上的资源。在Poco库中提供了POCO::URI、POCO::URIStreamFactory、POCO::URIStreamOpener类来对URI信息进行管理。其中POCO::URI用于进行URI操作和存储。URIStreamFactory可以打开一个URI资源,并且把该URI资源和一个输入流相关联。URIStreamOpener类用来设计成对URIStreamFactory进行管理。通过URIStreamFactory和URIStreamOpener可以把对所有资源的读取都适配一个流接口。
下面是Poco中Uri部分的类图。
2. POCO::URI
一个URI标志通常包括下列部分:Scheme:协议
Authority:包括了主机地址、端口、用户信息(通常指用户名/密码)
Path: 路径
Query: 查询
Fragment: 内部资源地址
下面是URI的一些例子:
http :// www.google.com / search ? q=POCO | | | | | | | | Scheme Host Path Query
http :// appinf.com / poco/docs/Poco.URI.html # 5589 | | | | | | | | Scheme Host Path Fragment
ftp :// anonymous @ upload.sourceforge.com / incoming | | | | | | | | Scheme User Host Path
POCO::URI类可以被看成是URI标记的集合。其接口定义如下:
class Foundation_API URI { public: URI(); /// Creates an empty URI. explicit URI(const std::string& uri); /// Parses an URI from the given string. Throws a /// SyntaxException if the uri is not valid. explicit URI(const char* uri); /// Parses an URI from the given string. Throws a /// SyntaxException if the uri is not valid. URI(const std::string& scheme, const std::string& pathEtc); /// Creates an URI from its parts. URI(const std::string& scheme, const std::string& authority, const std::string& pathEtc); /// Creates an URI from its parts. URI(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query); /// Creates an URI from its parts. URI(const std::string& scheme, const std::string& authority, const std::string& path, const std::string& query, const std::string& fragment); /// Creates an URI from its parts. URI(const URI& uri); /// Copy constructor. Creates an URI from another one. URI(const URI& baseURI, const std::string& relativeURI); /// Creates an URI from a base URI and a relative URI, according to /// the algorithm in section 5.2 of RFC 3986. ~URI(); /// Destroys the URI. URI& operator = (const URI& uri); /// Assignment operator. URI& operator = (const std::string& uri); /// Parses and assigns an URI from the given string. Throws a /// SyntaxException if the uri is not valid. URI& operator = (const char* uri); /// Parses and assigns an URI from the given string. Throws a /// SyntaxException if the uri is not valid. void swap(URI& uri); /// Swaps the URI with another one. void clear(); /// Clears all parts of the URI. std::string toString() const; /// Returns a string representation of the URI. /// /// Characters in the path, query and fragment parts will be /// percent-encoded as necessary. const std::string& getScheme() const; /// Returns the scheme part of the URI. void setScheme(const std::string& scheme); /// Sets the scheme part of the URI. The given scheme /// is converted to lower-case. /// /// A list of registered URI schemes can be found /// at <http://www.iana.org/assignments/uri-schemes>. const std::string& getUserInfo() const; /// Returns the user-info part of the URI. void setUserInfo(const std::string& userInfo); /// Sets the user-info part of the URI. const std::string& getHost() const; /// Returns the host part of the URI. void setHost(const std::string& host); /// Sets the host part of the URI. unsigned short getPort() const; /// Returns the port number part of the URI. /// /// If no port number (0) has been specified, the /// well-known port number (e.g., 80 for http) for /// the given scheme is returned if it is known. /// Otherwise, 0 is returned. void setPort(unsigned short port); /// Sets the port number part of the URI. std::string getAuthority() const; /// Returns the authority part (userInfo, host and port) /// of the URI. /// /// If the port number is a well-known port /// number for the given scheme (e.g., 80 for http), it /// is not included in the authority. void setAuthority(const std::string& authority); /// Parses the given authority part for the URI and sets /// the user-info, host, port components accordingly. const std::string& getPath() const; /// Returns the path part of the URI. void setPath(const std::string& path); /// Sets the path part of the URI. std::string getQuery() const; /// Returns the query part of the URI. void setQuery(const std::string& query); /// Sets the query part of the URI. const std::string& getRawQuery() const; /// Returns the unencoded query part of the URI. void setRawQuery(const std::string& query); /// Sets the query part of the URI. const std::string& getFragment() const; /// Returns the fragment part of the URI. void setFragment(const std::string& fragment); /// Sets the fragment part of the URI. void setPathEtc(const std::string& pathEtc); /// Sets the path, query and fragment parts of the URI. std::string getPathEtc() const; /// Returns the path, query and fragment parts of the URI. std::string getPathAndQuery() const; /// Returns the path and query parts of the URI. void resolve(const std::string& relativeURI); /// Resolves the given relative URI against the base URI. /// See section 5.2 of RFC 3986 for the algorithm used. void resolve(const URI& relativeURI); /// Resolves the given relative URI against the base URI. /// See section 5.2 of RFC 3986 for the algorithm used. bool isRelative() const; /// Returns true if the URI is a relative reference, false otherwise. /// /// A relative reference does not contain a scheme identifier. /// Relative references are usually resolved against an absolute /// base reference. bool empty() const; /// Returns true if the URI is empty, false otherwise. bool operator == (const URI& uri) const; /// Returns true if both URIs are identical, false otherwise. /// /// Two URIs are identical if their scheme, authority, /// path, query and fragment part are identical. bool operator == (const std::string& uri) const; /// Parses the given URI and returns true if both URIs are identical, /// false otherwise. bool operator != (const URI& uri) const; /// Returns true if both URIs are identical, false otherwise. bool operator != (const std::string& uri) const; /// Parses the given URI and returns true if both URIs are identical, /// false otherwise. void normalize(); /// Normalizes the URI by removing all but leading . and .. segments from the path. /// /// If the first path segment in a relative path contains a colon (:), /// such as in a Windows path containing a drive letter, a dot segment (./) /// is prepended in accordance with section 3.3 of RFC 3986. void getPathSegments(std::vector<std::string>& segments); /// Places the single path segments (delimited by slashes) into the /// given vector. static void encode(const std::string& str, const std::string& reserved, std::string& encodedStr); /// URI-encodes the given string by escaping reserved and non-ASCII /// characters. The encoded string is appended to encodedStr. static void decode(const std::string& str, std::string& decodedStr); /// URI-decodes the given string by replacing percent-encoded /// characters with the actual character. The decoded string /// is appended to decodedStr. .... private: std::string _scheme; std::string _userInfo; std::string _host; unsigned short _port; std::string _path; std::string _query; std::string _fragment; };
可以看到,在POCO::URI内部单独定义了不同字段来对应存储URI的不同部分。值得注意到是,在POCO::URI中存在两个函静态数encode()和decode()。这两个函数用来对URI资源进行Percent-encoding编码。这是由于在URI标准中定义了一些保留字符,如果URI资源中存在保留字符,必须对它们进行转义。
下面是其一个例子:
#include "Poco/URI.h" #include <iostream> int main(int argc, char** argv) { Poco::URI uri1("http://www.appinf.com:88/sample?example-query#frag"); std::string scheme(uri1.getScheme()); // "http" std::string auth(uri1.getAuthority()); // "www.appinf.com:88" std::string host(uri1.getHost()); // "www.appinf.com" unsigned short port = uri1.getPort(); // 88 std::string path(uri1.getPath()); // "/sample" std::string query(uri1.getQuery()); // "example-query" std::string frag(uri1.getFragment()); // "frag" std::string pathEtc(uri1.getPathEtc()); // "/sample?examplequery#frag" Poco::URI uri2; uri2.setScheme("https"); uri2.setAuthority("www.appinf.com"); uri2.setPath("/another sample"); std::string s(uri2.toString()); // "https://www.appinf.com/another%20sample" Poco::URI uri3("http://www.appinf.com"); uri3.resolve("/poco/info/index.html"); s = uri3.toString(); // "http://www.appinf.com/poco/info/index.html" uri3.resolve("support.html"); s = uri3.toString(); // "http://www.appinf.com/poco/info/support.html" uri3.resolve("http://sourceforge.net/projects/poco"); s = uri3.toString(); // "http://sourceforge.net/projects/poco" return 0; }
3. POCO::URIStreamOpener
POCO::URIStreamOpener类主要用于为URI资源,创建并打开一个对应的输入流。对于每一种URI协议,Poco::URIStreamFactory的子类必须向POCO::URIStreamOpener注册。在Poco库中,内置了文件(包括网络文件) 流工厂类FileStreamFactory,HTTP流工厂类 HTTPStreamFactory,FTP流工厂类 FTPStreamFactory。
下面是其一个例子:
#include "Poco/URIStreamOpener.h" #include "Poco/Net/HTTPStreamFactory.h" #include "Poco/Net/FTPStreamFactory.h" #include <memory> int main(int argc, char** argv) { Poco::Net::HTTPStreamFactory::registerFactory(); Poco::Net::FTPStreamFactory::registerFactory(); Poco::URIStreamOpener& opener = Poco::URIStreamOpener::defaultOpener(); std::auto_ptr<std::istream> istr1( opener.open("http://www.appinf.com/index.html") ); std::auto_ptr<std::istream> istr2( opener.open("ftp://ftp.appinf.com/pub/poco/poco-1.2.5.tar.gz") ); std::auto_ptr<std::istream> istr3( opener.open("file:///usr/include/stdio.h") ); return 0; }