|
13 | 13 | #include <cef3/cef/include/cef_parser.h> |
14 | 14 | #include "CAjaxResourceHandler.h" |
15 | 15 |
|
16 | | -CefRefPtr<CefResourceHandler> CWebApp::HandleError(const SString& strError, unsigned int uiError) |
| 16 | +[[nodiscard]] CefRefPtr<CefResourceHandler> CWebApp::HandleError(const SString& strError, unsigned int uiError) |
17 | 17 | { |
18 | | - auto stream = CefStreamReader::CreateForData((void*)strError.c_str(), strError.length()); |
19 | | - return new CefStreamResourceHandler(uiError, strError, "text/plain", CefResponse::HeaderMap(), stream); |
| 18 | + auto stream = CefStreamReader::CreateForData( |
| 19 | + (void*)strError.c_str(), |
| 20 | + strError.length() |
| 21 | + ); |
| 22 | + if (!stream) |
| 23 | + return nullptr; |
| 24 | + return CefRefPtr<CefResourceHandler>(new CefStreamResourceHandler(uiError, strError, "text/plain", CefResponse::HeaderMap(), stream)); |
20 | 25 | } |
21 | 26 |
|
22 | 27 | void CWebApp::OnBeforeCommandLineProcessing(const CefString& process_type, CefRefPtr<CefCommandLine> command_line) |
23 | 28 | { |
24 | | - CWebCore* pWebCore = static_cast<CWebCore*>(g_pCore->GetWebCore()); |
| 29 | + if (!command_line) |
| 30 | + return; |
| 31 | + |
| 32 | + const auto pWebCore = static_cast<CWebCore*>(g_pCore->GetWebCore()); |
| 33 | + if (!pWebCore) |
| 34 | + return; |
25 | 35 |
|
26 | 36 | if (!pWebCore->GetGPUEnabled()) |
27 | 37 | command_line->AppendSwitch("disable-gpu"); |
@@ -52,129 +62,174 @@ CefRefPtr<CefResourceHandler> CWebApp::Create(CefRefPtr<CefBrowser> browser, Cef |
52 | 62 | // browser or frame are NULL if the request does not orginate from a browser window |
53 | 63 | // This is for exmaple true for the application cache or CEFURLRequests |
54 | 64 | // (https://www.html5rocks.com/en/tutorials/appcache/beginner/) |
55 | | - if (!browser || !frame) |
| 65 | + if (!browser || !frame || !request) |
| 66 | + return nullptr; |
| 67 | + |
| 68 | + const auto pWebCore = static_cast<CWebCore*>(g_pCore->GetWebCore()); |
| 69 | + if (!pWebCore) |
56 | 70 | return nullptr; |
57 | 71 |
|
58 | | - CWebCore* pWebCore = static_cast<CWebCore*>(g_pCore->GetWebCore()); |
59 | | - auto pWebView = pWebCore->FindWebView(browser); |
| 72 | + auto pWebView = pWebCore->FindWebView(browser); |
60 | 73 | if (!pWebView || !pWebView->IsLocal()) |
61 | 74 | return nullptr; |
62 | 75 |
|
63 | 76 | CefURLParts urlParts; |
64 | 77 | if (!CefParseURL(request->GetURL(), urlParts)) |
65 | 78 | return nullptr; |
66 | 79 |
|
| 80 | + if (!urlParts.host.str) |
| 81 | + return nullptr; |
| 82 | + |
67 | 83 | SString host = UTF16ToMbUTF8(urlParts.host.str); |
68 | 84 | if (scheme_name == "http" && host == "mta") |
69 | 85 | { |
70 | 86 | // Scheme format: https://mta/resourceName/file.html or https://mta/local/file.html for the current resource |
71 | 87 |
|
72 | 88 | // Get resource name and path |
73 | | - SString path = UTF16ToMbUTF8(urlParts.path.str).substr(1); // Remove slash at the front |
74 | | - size_t slashPos = path.find('/'); |
75 | | - if (slashPos == std::string::npos) |
| 89 | + if (!urlParts.path.str) |
76 | 90 | return HandleError("404 - Not found", 404); |
77 | 91 |
|
78 | | - SString resourceName = path.substr(0, slashPos); |
79 | | - SString resourcePath = path.substr(slashPos + 1); |
80 | | - |
81 | | - if (resourcePath.empty()) |
| 92 | + SString path = UTF16ToMbUTF8(urlParts.path.str); |
| 93 | + if (std::size(path) < 2) |
82 | 94 | return HandleError("404 - Not found", 404); |
83 | 95 |
|
84 | | - // Get mime type from extension |
85 | | - CefString mimeType; |
86 | | - size_t pos = resourcePath.find_last_of('.'); |
87 | | - if (pos != std::string::npos) |
88 | | - mimeType = CefGetMimeType(resourcePath.substr(pos + 1)); |
89 | | - |
90 | | - // Make sure we provide a mime type, even |
91 | | - // when we cannot deduct it from the file extension |
92 | | - if (mimeType.empty()) |
93 | | - mimeType = "application/octet-stream"; |
94 | | - |
95 | | - if (pWebView->HasAjaxHandler(resourcePath)) |
| 96 | + path = path.substr(1); // Remove slash at the front |
| 97 | + if (const auto slashPos = path.find('/'); slashPos == std::string::npos) |
96 | 98 | { |
97 | | - std::vector<SString> vecGet; |
98 | | - std::vector<SString> vecPost; |
| 99 | + static constexpr auto ERROR_404 = "404 - Not found"; |
| 100 | + static constexpr unsigned int CODE_404 = 404; |
| 101 | + return HandleError(ERROR_404, CODE_404); |
| 102 | + } |
| 103 | + else |
| 104 | + { |
| 105 | + SString resourceName = path.substr(0, slashPos); |
| 106 | + SString resourcePath = path.substr(slashPos + 1); |
99 | 107 |
|
100 | | - if (urlParts.query.str != nullptr) |
| 108 | + if (resourcePath.empty()) |
101 | 109 | { |
102 | | - SString strGet = UTF16ToMbUTF8(urlParts.query.str); |
103 | | - std::vector<SString> vecTmp; |
104 | | - strGet.Split("&", vecTmp); |
| 110 | + static constexpr auto ERROR_404 = "404 - Not found"; |
| 111 | + static constexpr unsigned int CODE_404 = 404; |
| 112 | + return HandleError(ERROR_404, CODE_404); |
| 113 | + } |
105 | 114 |
|
106 | | - SString key; |
107 | | - SString value; |
108 | | - for (auto&& param : vecTmp) |
109 | | - { |
110 | | - param.Split("=", &key, &value); |
111 | | - vecGet.push_back(key); |
112 | | - vecGet.push_back(value); |
113 | | - } |
| 115 | + // Get mime type from extension |
| 116 | + CefString mimeType; |
| 117 | + if (const auto pos = resourcePath.find_last_of('.'); pos != std::string::npos) |
| 118 | + mimeType = CefGetMimeType(resourcePath.substr(pos + 1)); |
| 119 | + |
| 120 | + // Make sure we provide a mime type, even |
| 121 | + // when we cannot deduct it from the file extension |
| 122 | + if (mimeType.empty()) |
| 123 | + { |
| 124 | + mimeType = "application/octet-stream"; |
114 | 125 | } |
115 | 126 |
|
116 | | - CefPostData::ElementVector vecPostElements; |
117 | | - auto postData = request->GetPostData(); |
118 | | - if (postData.get()) |
| 127 | + if (pWebView->HasAjaxHandler(resourcePath)) |
119 | 128 | { |
120 | | - request->GetPostData()->GetElements(vecPostElements); |
| 129 | + std::vector<SString> vecGet; |
| 130 | + std::vector<SString> vecPost; |
121 | 131 |
|
122 | | - SString key; |
123 | | - SString value; |
124 | | - for (auto&& post : vecPostElements) |
| 132 | + if (urlParts.query.str) |
125 | 133 | { |
126 | | - // Limit to 5MiB and allow byte data only |
127 | | - size_t bytesCount = post->GetBytesCount(); |
128 | | - if (bytesCount > 5 * 1024 * 1024 || post->GetType() != CefPostDataElement::Type::PDE_TYPE_BYTES) |
129 | | - continue; |
130 | | - |
131 | | - // Make string from buffer |
132 | | - std::unique_ptr<char[]> buffer{new char[bytesCount]}; |
133 | | - post->GetBytes(bytesCount, buffer.get()); |
134 | | - SStringX param(buffer.get(), bytesCount); |
135 | | - |
136 | | - // Parse POST data into vector |
| 134 | + SString strGet = UTF16ToMbUTF8(urlParts.query.str); |
137 | 135 | std::vector<SString> vecTmp; |
138 | | - param.Split("&", vecTmp); |
| 136 | + vecTmp.reserve(8); // Reserve space for common query parameter count |
| 137 | + strGet.Split("&", vecTmp); |
139 | 138 |
|
| 139 | + SString key; |
| 140 | + SString value; |
140 | 141 | for (auto&& param : vecTmp) |
141 | 142 | { |
142 | 143 | param.Split("=", &key, &value); |
143 | | - vecPost.push_back(key); |
144 | | - vecPost.push_back(value); |
| 144 | + vecGet.push_back(key); |
| 145 | + vecGet.push_back(value); |
145 | 146 | } |
146 | 147 | } |
147 | | - } |
148 | 148 |
|
149 | | - auto handler = new CAjaxResourceHandler(vecGet, vecPost, mimeType); |
150 | | - pWebView->HandleAjaxRequest(resourcePath, handler); |
151 | | - return handler; |
152 | | - } |
153 | | - else |
154 | | - { |
155 | | - // Calculate MTA resource path |
156 | | - if (resourceName != "local") |
157 | | - path = ":" + resourceName + "/" + resourcePath; |
| 149 | + CefPostData::ElementVector vecPostElements; |
| 150 | + if (auto postData = request->GetPostData(); postData) |
| 151 | + { |
| 152 | + postData->GetElements(vecPostElements); |
| 153 | + |
| 154 | + SString key; |
| 155 | + SString value; |
| 156 | + for (auto&& post : vecPostElements) |
| 157 | + { |
| 158 | + // Limit to 5MiB and allow byte data only |
| 159 | + constexpr size_t MAX_POST_SIZE = 5 * 1024 * 1024; |
| 160 | + size_t bytesCount = post->GetBytesCount(); |
| 161 | + if (bytesCount > MAX_POST_SIZE || post->GetType() != CefPostDataElement::Type::PDE_TYPE_BYTES) |
| 162 | + continue; |
| 163 | + |
| 164 | + // Make string from buffer |
| 165 | + auto buffer = std::make_unique<char[]>(bytesCount); |
| 166 | + // Verify GetBytes succeeded before using buffer |
| 167 | + size_t bytesRead = post->GetBytes(bytesCount, buffer.get()); |
| 168 | + if (bytesRead != bytesCount) |
| 169 | + continue; |
| 170 | + SStringX postParam(buffer.get(), bytesCount); |
| 171 | + |
| 172 | + // Parse POST data into vector |
| 173 | + std::vector<SString> vecTmp; |
| 174 | + vecTmp.reserve(8); |
| 175 | + postParam.Split("&", vecTmp); |
| 176 | + |
| 177 | + for (auto&& param : vecTmp) |
| 178 | + { |
| 179 | + param.Split("=", &key, &value); |
| 180 | + vecPost.push_back(key); |
| 181 | + vecPost.push_back(value); |
| 182 | + } |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + CefRefPtr<CAjaxResourceHandler> handler(new CAjaxResourceHandler(vecGet, vecPost, mimeType)); |
| 187 | + pWebView->HandleAjaxRequest(resourcePath, handler.get()); |
| 188 | + return handler; |
| 189 | + } |
158 | 190 | else |
159 | | - path = resourcePath; |
| 191 | + { |
| 192 | + // Calculate MTA resource path |
| 193 | + static constexpr auto LOCAL = "local"; |
| 194 | + path = (resourceName != LOCAL) ? ":" + resourceName + "/" + resourcePath : resourcePath; |
160 | 195 |
|
161 | | - // Calculate absolute path |
162 | | - if (!pWebView->GetFullPathFromLocal(path)) |
163 | | - return HandleError("404 - Not found", 404); |
| 196 | + // Calculate absolute path |
| 197 | + if (!pWebView->GetFullPathFromLocal(path)) |
| 198 | + { |
| 199 | + static constexpr auto ERROR_404 = "404 - Not found"; |
| 200 | + static constexpr unsigned int CODE_404 = 404; |
| 201 | + return HandleError(ERROR_404, CODE_404); |
| 202 | + } |
164 | 203 |
|
165 | | - // Verify local files |
166 | | - CBuffer fileData; |
167 | | - if (!pWebView->VerifyFile(path, fileData)) |
168 | | - return HandleError("403 - Access Denied", 403); |
| 204 | + // Verify local files |
| 205 | + CBuffer fileData; |
| 206 | + if (!pWebView->VerifyFile(path, fileData)) |
| 207 | + { |
| 208 | + static constexpr auto ERROR_403 = "403 - Access Denied"; |
| 209 | + static constexpr unsigned int CODE_403 = 403; |
| 210 | + return HandleError(ERROR_403, CODE_403); |
| 211 | + } |
169 | 212 |
|
170 | | - // Finally, load the file stream |
171 | | - if (fileData.GetData() == nullptr || fileData.GetSize() == 0) |
172 | | - fileData = CBuffer("", sizeof("")); |
| 213 | + // Finally, load the file stream |
| 214 | + if (!fileData.GetData() || fileData.GetSize() == 0) |
| 215 | + { |
| 216 | + static constexpr char emptyStr[] = ""; |
| 217 | + fileData = CBuffer(emptyStr, std::size(emptyStr)); |
| 218 | + } |
173 | 219 |
|
174 | | - auto stream = CefStreamReader::CreateForData(fileData.GetData(), fileData.GetSize()); |
175 | | - if (stream.get()) |
176 | | - return new CefStreamResourceHandler(mimeType, stream); |
177 | | - return HandleError("404 - Not found", 404); |
| 220 | + auto stream = CefStreamReader::CreateForData( |
| 221 | + fileData.GetData(), |
| 222 | + fileData.GetSize() |
| 223 | + ); |
| 224 | + if (!stream) |
| 225 | + { |
| 226 | + static constexpr auto ERROR_404 = "404 - Not found"; |
| 227 | + static constexpr unsigned int CODE_404 = 404; |
| 228 | + return HandleError(ERROR_404, CODE_404); |
| 229 | + } |
| 230 | + |
| 231 | + return CefRefPtr<CefResourceHandler>(new CefStreamResourceHandler(mimeType, stream)); |
| 232 | + } |
178 | 233 | } |
179 | 234 | } |
180 | 235 |
|
|
0 commit comments