1//
2// URIStreamOpener.cpp
3//
4// Library: Foundation
5// Package: URI
6// Module: URIStreamOpener
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/URIStreamOpener.h"
16#include "Poco/URIStreamFactory.h"
17#include "Poco/FileStreamFactory.h"
18#include "Poco/URI.h"
19#include "Poco/Path.h"
20#include "Poco/SingletonHolder.h"
21#include "Poco/Exception.h"
22
23
24namespace Poco {
25
26
27URIStreamOpener::URIStreamOpener()
28{
29 registerStreamFactory("file", new FileStreamFactory);
30}
31
32
33URIStreamOpener::~URIStreamOpener()
34{
35 for (FactoryMap::iterator it = _map.begin(); it != _map.end(); ++it)
36 delete it->second;
37}
38
39
40std::istream* URIStreamOpener::open(const URI& uri) const
41{
42 FastMutex::ScopedLock lock(_mutex);
43
44 std::string scheme;
45 if (uri.isRelative())
46 scheme = "file";
47 else
48 scheme = uri.getScheme();
49 return openURI(scheme, uri);
50}
51
52
53std::istream* URIStreamOpener::open(const std::string& pathOrURI) const
54{
55 FastMutex::ScopedLock lock(_mutex);
56
57 try
58 {
59 URI uri(pathOrURI);
60 std::string scheme(uri.getScheme());
61 FactoryMap::const_iterator it = _map.find(scheme);
62 if (it != _map.end())
63 {
64 return openURI(scheme, uri);
65 }
66 else if (scheme.length() <= 1) // could be Windows path
67 {
68 Path path;
69 if (path.tryParse(pathOrURI, Path::PATH_GUESS))
70 {
71 return openFile(path);
72 }
73 }
74 throw UnknownURISchemeException(pathOrURI);
75 }
76 catch (URISyntaxException&)
77 {
78 Path path;
79 if (path.tryParse(pathOrURI, Path::PATH_GUESS))
80 return openFile(path);
81 else
82 throw;
83 }
84}
85
86
87std::istream* URIStreamOpener::open(const std::string& basePathOrURI, const std::string& pathOrURI) const
88{
89 FastMutex::ScopedLock lock(_mutex);
90
91 try
92 {
93 URI uri(basePathOrURI);
94 std::string scheme(uri.getScheme());
95 FactoryMap::const_iterator it = _map.find(scheme);
96 if (it != _map.end())
97 {
98 uri.resolve(pathOrURI);
99 scheme = uri.getScheme();
100 return openURI(scheme, uri);
101 }
102 else if (scheme.length() <= 1) // could be Windows path
103 {
104 Path base;
105 Path path;
106 if (base.tryParse(basePathOrURI, Path::PATH_GUESS) && path.tryParse(pathOrURI, Path::PATH_GUESS))
107 {
108 base.resolve(path);
109 return openFile(base);
110 }
111 }
112 throw UnknownURISchemeException(basePathOrURI);
113 }
114 catch (URISyntaxException&)
115 {
116 Path base;
117 Path path;
118 if (base.tryParse(basePathOrURI, Path::PATH_GUESS) && path.tryParse(pathOrURI, Path::PATH_GUESS))
119 {
120 base.resolve(path);
121 return openFile(base);
122 }
123 else throw;
124 }
125}
126
127
128void URIStreamOpener::registerStreamFactory(const std::string& scheme, URIStreamFactory* pFactory)
129{
130 poco_check_ptr (pFactory);
131
132 FastMutex::ScopedLock lock(_mutex);
133 if (_map.find(scheme) == _map.end())
134 {
135 _map[scheme] = pFactory;
136 }
137 else throw ExistsException("An URIStreamFactory for the given scheme has already been registered", scheme);
138}
139
140
141void URIStreamOpener::unregisterStreamFactory(const std::string& scheme)
142{
143 FastMutex::ScopedLock lock(_mutex);
144
145 FactoryMap::iterator it = _map.find(scheme);
146 if (it != _map.end())
147 {
148 URIStreamFactory* pFactory = it->second;
149 _map.erase(it);
150 delete pFactory;
151 }
152 else throw NotFoundException("No URIStreamFactory has been registered for the given scheme", scheme);
153}
154
155
156bool URIStreamOpener::supportsScheme(const std::string& scheme)
157{
158 FastMutex::ScopedLock lock(_mutex);
159 return _map.find(scheme) != _map.end();
160}
161
162
163namespace
164{
165 static SingletonHolder<URIStreamOpener> sh;
166}
167
168
169URIStreamOpener& URIStreamOpener::defaultOpener()
170{
171 return *sh.get();
172}
173
174
175std::istream* URIStreamOpener::openFile(const Path& path) const
176{
177 FileStreamFactory factory;
178 return factory.open(path);
179}
180
181
182std::istream* URIStreamOpener::openURI(const std::string& scheme, const URI& uri) const
183{
184 std::string actualScheme(scheme);
185 URI actualURI(uri);
186 int redirects = 0;
187
188 while (redirects < MAX_REDIRECTS)
189 {
190 try
191 {
192 FactoryMap::const_iterator it = _map.find(actualScheme);
193 if (it != _map.end())
194 return it->second->open(actualURI);
195 else if (redirects > 0)
196 throw UnknownURISchemeException(actualURI.toString() + std::string("; redirected from ") + uri.toString());
197 else
198 throw UnknownURISchemeException(actualURI.toString());
199 }
200 catch (URIRedirection& redir)
201 {
202 actualURI = redir.uri();
203 actualScheme = actualURI.getScheme();
204 ++redirects;
205 }
206 }
207 throw TooManyURIRedirectsException(uri.toString());
208}
209
210
211} // namespace Poco
212