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;
}