Make statSyscall in ext_file.cpp support relative paths by default.
[hiphop-php.git] / hphp / runtime / base / stream-wrapper-registry.cpp
blob3190e0eff7267c707a7d24e9079f7acaf5e8e306
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/stream-wrapper-registry.h"
18 #include "hphp/runtime/base/file.h"
19 #include "hphp/runtime/base/file-stream-wrapper.h"
20 #include "hphp/runtime/base/php-stream-wrapper.h"
21 #include "hphp/runtime/base/http-stream-wrapper.h"
22 #include "hphp/runtime/base/data-stream-wrapper.h"
23 #include "hphp/runtime/base/glob-stream-wrapper.h"
24 #include "hphp/runtime/base/request-local.h"
25 #include "hphp/runtime/base/request-event-handler.h"
26 #include "hphp/runtime/ext/ext_string.h"
27 #include <set>
28 #include <map>
29 #include <algorithm>
30 #include <memory>
32 namespace HPHP { namespace Stream {
33 ///////////////////////////////////////////////////////////////////////////////
35 namespace {
36 struct RequestWrappers final : RequestEventHandler {
37 void requestInit() override {}
38 void requestShutdown() override {
39 m_disabled.clear();
40 m_wrappers.clear();
43 std::set<String> m_disabled;
44 std::map<String,std::unique_ptr<Wrapper>> m_wrappers;
46 } // empty namespace
48 typedef std::map<std::string,Wrapper*> wrapper_map_t;
50 // Global registry for wrappers
51 static wrapper_map_t s_wrappers;
53 // Request local registry for user defined wrappers and disabled builtins
54 IMPLEMENT_STATIC_REQUEST_LOCAL(RequestWrappers, s_request_wrappers);
56 bool registerWrapper(const std::string &scheme, Wrapper *wrapper) {
57 assert(s_wrappers.find(scheme) == s_wrappers.end());
58 s_wrappers[scheme] = wrapper;
59 return true;
62 const StaticString
63 s_file("file"),
64 s_compress_zlib("compress.zlib"),
65 s_data("data");
67 bool disableWrapper(const String& scheme) {
68 String lscheme = f_strtolower(scheme);
70 if (lscheme.same(s_file)) {
71 // Zend quietly succeeds, but does nothing
72 return true;
75 bool ret = false;
77 // Unregister request-specific wrappers entirely
78 if (s_request_wrappers->m_wrappers.find(lscheme) !=
79 s_request_wrappers->m_wrappers.end()) {
80 s_request_wrappers->m_wrappers.erase(lscheme);
81 ret = true;
84 // Disable builtin wrapper if it exists
85 if (s_wrappers.find(lscheme.data()) == s_wrappers.end()) {
86 // No builtin to disable
87 return ret;
90 if (s_request_wrappers->m_disabled.find(lscheme) !=
91 s_request_wrappers->m_disabled.end()) {
92 // Already disabled
93 return ret;
96 // Disable it
97 s_request_wrappers->m_disabled.insert(lscheme);
98 return true;
101 bool restoreWrapper(const String& scheme) {
102 String lscheme = f_strtolower(scheme);
103 bool ret = false;
105 // Unregister request-specific wrapper
106 if (s_request_wrappers->m_wrappers.find(lscheme) !=
107 s_request_wrappers->m_wrappers.end()) {
108 s_request_wrappers->m_wrappers.erase(lscheme);
109 ret = true;
112 // Un-disable builtin wrapper
113 if (s_request_wrappers->m_disabled.find(lscheme) ==
114 s_request_wrappers->m_disabled.end()) {
115 // Not disabled
116 return ret;
119 // Perform action un-disable
120 s_request_wrappers->m_disabled.erase(lscheme);
121 return true;
124 bool registerRequestWrapper(const String& scheme,
125 std::unique_ptr<Wrapper> wrapper) {
126 String lscheme = f_strtolower(scheme);
128 // Global, non-disabled wrapper
129 if ((s_wrappers.find(lscheme.data()) != s_wrappers.end()) &&
130 (s_request_wrappers->m_disabled.find(lscheme) ==
131 s_request_wrappers->m_disabled.end())) {
132 return false;
135 // A wrapper has already been registered for that scheme
136 if (s_request_wrappers->m_wrappers.find(lscheme) !=
137 s_request_wrappers->m_wrappers.end()) {
138 return false;
141 s_request_wrappers->m_wrappers[lscheme] = std::move(wrapper);
142 return true;
145 Array enumWrappers() {
146 Array ret = Array::Create();
148 // Enum global wrappers which are not disabled
149 for (auto it = s_wrappers.begin(); it != s_wrappers.end(); ++it) {
150 if (s_request_wrappers->m_disabled.find(it->first) ==
151 s_request_wrappers->m_disabled.end()) {
152 ret.append(it->first);
156 // Enum request local wrappers
157 for (auto it = s_request_wrappers->m_wrappers.begin();
158 it != s_request_wrappers->m_wrappers.end(); ++it) {
159 ret.append(it->first);
161 return ret;
164 Wrapper* getWrapper(const String& scheme) {
165 String lscheme = f_strtolower(scheme);
167 // Request local wrapper?
169 auto it = s_request_wrappers->m_wrappers.find(lscheme);
170 if (it != s_request_wrappers->m_wrappers.end()) {
171 return it->second.get();
175 // Global, non-disabled wrapper?
177 auto it = s_wrappers.find(lscheme.data());
178 if ((it != s_wrappers.end()) &&
179 (s_request_wrappers->m_disabled.find(lscheme) ==
180 s_request_wrappers->m_disabled.end())) {
181 return it->second;
185 return nullptr;
188 Wrapper* getWrapperFromURI(const String& uri, int* pathIndex /* = NULL */) {
189 const char *uri_string = uri.data();
191 /* Special case for PHP4 Backward Compatability */
192 if (!strncasecmp(uri_string, "zlib:", sizeof("zlib:") - 1)) {
193 return getWrapper(s_compress_zlib);
196 // data wrapper can come with or without a double forward slash
197 if (!strncasecmp(uri_string, "data:", sizeof("data:") - 1)) {
198 return getWrapper(s_data);
201 const char *colon = strstr(uri_string, "://");
202 if (!colon) {
203 return getWrapper(s_file);
206 int len = colon - uri_string;
207 if (pathIndex != nullptr) *pathIndex = len + sizeof("://") - 1;
208 if (Wrapper *w = getWrapper(String(uri_string, len, CopyString))) {
209 return w;
211 return getWrapper(s_file);
214 static FileStreamWrapper s_file_stream_wrapper;
215 static PhpStreamWrapper s_php_stream_wrapper;
216 static HttpStreamWrapper s_http_stream_wrapper;
217 static DataStreamWrapper s_data_stream_wrapper;
218 static GlobStreamWrapper s_glob_stream_wrapper;
220 void RegisterCoreWrappers() {
221 s_file_stream_wrapper.registerAs("file");
222 s_php_stream_wrapper.registerAs("php");
223 s_http_stream_wrapper.registerAs("http");
224 s_http_stream_wrapper.registerAs("https");
225 s_data_stream_wrapper.registerAs("data");
226 s_glob_stream_wrapper.registerAs("glob");
229 ///////////////////////////////////////////////////////////////////////////////