Mercurial > hg > orthanc
comparison Plugins/Samples/ServeFolders/Plugin.cpp @ 2168:84033563f7f0
ServeFolders: Better protection against exceptions in the callbacks
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 22 Nov 2016 14:38:25 +0100 |
parents | aa2915963531 |
children | d15de5685ad8 |
comparison
equal
deleted
inserted
replaced
2167:aa2915963531 | 2168:84033563f7f0 |
---|---|
28 | 28 |
29 static OrthancPluginContext* context_ = NULL; | 29 static OrthancPluginContext* context_ = NULL; |
30 static std::map<std::string, std::string> extensions_; | 30 static std::map<std::string, std::string> extensions_; |
31 static std::map<std::string, std::string> folders_; | 31 static std::map<std::string, std::string> folders_; |
32 static const char* INDEX_URI = "/app/plugin-serve-folders.html"; | 32 static const char* INDEX_URI = "/app/plugin-serve-folders.html"; |
33 static bool allowCache_ = true; | 33 static bool allowCache_ = false; |
34 static bool generateETag_ = true; // TODO parameter | 34 static bool generateETag_ = true; |
35 | 35 |
36 | 36 |
37 static void SetHttpHeaders(OrthancPluginRestOutput* output) | 37 static void SetHttpHeaders(OrthancPluginRestOutput* output) |
38 { | 38 { |
39 if (!allowCache_) | 39 if (!allowCache_) |
79 { | 79 { |
80 return found->second; | 80 return found->second; |
81 } | 81 } |
82 else | 82 else |
83 { | 83 { |
84 OrthancPlugins::LogWarning(context_, "ServeFolders- Unknown MIME type for extension: " + extension); | 84 OrthancPlugins::LogWarning(context_, "ServeFolders: Unknown MIME type for extension \"" + extension + "\""); |
85 return "application/octet-stream"; | 85 return "application/octet-stream"; |
86 } | |
87 } | |
88 | |
89 | |
90 static bool ReadFile(std::string& target, | |
91 const std::string& path) | |
92 { | |
93 try | |
94 { | |
95 OrthancPlugins::MemoryBuffer buffer(context_); | |
96 buffer.ReadFile(path); | |
97 buffer.ToString(target); | |
98 return true; | |
99 } | |
100 catch (OrthancPlugins::PluginException&) | |
101 { | |
102 return false; | |
103 } | 86 } |
104 } | 87 } |
105 | 88 |
106 | 89 |
107 static bool LookupFolder(std::string& folder, | 90 static bool LookupFolder(std::string& folder, |
123 return true; | 106 return true; |
124 } | 107 } |
125 } | 108 } |
126 | 109 |
127 | 110 |
128 static OrthancPluginErrorCode FolderCallback(OrthancPluginRestOutput* output, | 111 void ServeFolder(OrthancPluginRestOutput* output, |
129 const char* url, | 112 const char* url, |
130 const OrthancPluginHttpRequest* request) | 113 const OrthancPluginHttpRequest* request) |
131 { | 114 { |
132 namespace fs = boost::filesystem; | 115 namespace fs = boost::filesystem; |
133 | 116 |
134 if (request->method != OrthancPluginHttpMethod_Get) | 117 if (request->method != OrthancPluginHttpMethod_Get) |
135 { | 118 { |
136 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | 119 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); |
137 return OrthancPluginErrorCode_Success; | 120 return; |
138 } | 121 } |
139 | 122 |
140 std::string folder; | 123 std::string folder; |
141 | 124 |
142 if (LookupFolder(folder, output, request)) | 125 if (LookupFolder(folder, output, request)) |
187 else | 170 else |
188 { | 171 { |
189 std::string path = folder + "/" + item.string(); | 172 std::string path = folder + "/" + item.string(); |
190 std::string mime = GetMimeType(path); | 173 std::string mime = GetMimeType(path); |
191 | 174 |
192 std::string s; | 175 OrthancPlugins::MemoryBuffer content(context_); |
193 if (ReadFile(s, path)) | 176 |
194 { | 177 try |
195 const char* resource = s.size() ? s.c_str() : NULL; | 178 { |
196 | 179 content.ReadFile(path); |
197 if (generateETag_) | 180 } |
198 { | 181 catch (OrthancPlugins::PluginException&) |
199 OrthancPlugins::OrthancString md5(context_, OrthancPluginComputeMd5(context_, resource, s.size())); | 182 { |
200 std::string etag = "\"" + std::string(md5.GetContent()) + "\""; | 183 throw OrthancPlugins::PluginException(OrthancPluginErrorCode_InexistentFile); |
201 OrthancPluginSetHttpHeader(context_, output, "ETag", etag.c_str()); | 184 } |
202 } | 185 |
203 | 186 if (generateETag_) |
204 boost::posix_time::ptime lastModification = boost::posix_time::from_time_t(fs::last_write_time(path)); | 187 { |
205 std::string t = boost::posix_time::to_iso_string(lastModification); | 188 OrthancPlugins::OrthancString md5(context_, OrthancPluginComputeMd5(context_, content.GetData(), content.GetSize())); |
206 OrthancPluginSetHttpHeader(context_, output, "Last-Modified", t.c_str()); | 189 std::string etag = "\"" + std::string(md5.GetContent()) + "\""; |
207 | 190 OrthancPluginSetHttpHeader(context_, output, "ETag", etag.c_str()); |
208 SetHttpHeaders(output); | 191 } |
209 OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime.c_str()); | 192 |
210 } | 193 boost::posix_time::ptime lastModification = boost::posix_time::from_time_t(fs::last_write_time(path)); |
211 else | 194 std::string t = boost::posix_time::to_iso_string(lastModification); |
212 { | 195 OrthancPluginSetHttpHeader(context_, output, "Last-Modified", t.c_str()); |
213 OrthancPlugins::LogError(context_, "Inexistent file in served folder: " + path); | 196 |
214 OrthancPluginSendHttpStatusCode(context_, output, 404); | 197 SetHttpHeaders(output); |
215 } | 198 OrthancPluginAnswerBuffer(context_, output, content.GetData(), content.GetSize(), mime.c_str()); |
216 } | 199 } |
217 } | 200 } |
218 | 201 } |
219 return OrthancPluginErrorCode_Success; | 202 |
220 } | 203 |
221 | 204 void ListServedFolders(OrthancPluginRestOutput* output, |
222 | 205 const char* url, |
223 static OrthancPluginErrorCode ListServedFolders(OrthancPluginRestOutput* output, | 206 const OrthancPluginHttpRequest* request) |
224 const char* url, | |
225 const OrthancPluginHttpRequest* request) | |
226 { | 207 { |
227 if (request->method != OrthancPluginHttpMethod_Get) | 208 if (request->method != OrthancPluginHttpMethod_Get) |
228 { | 209 { |
229 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); | 210 OrthancPluginSendMethodNotAllowed(context_, output, "GET"); |
230 return OrthancPluginErrorCode_Success; | 211 return; |
231 } | 212 } |
232 | 213 |
233 std::string s = "<html><body><h1>Additional folders served by Orthanc</h1>\n"; | 214 std::string s = "<html><body><h1>Additional folders served by Orthanc</h1>\n"; |
234 | 215 |
235 if (folders_.empty()) | 216 if (folders_.empty()) |
251 | 232 |
252 s += "</body></html>\n"; | 233 s += "</body></html>\n"; |
253 | 234 |
254 SetHttpHeaders(output); | 235 SetHttpHeaders(output); |
255 OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html"); | 236 OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html"); |
256 | |
257 return OrthancPluginErrorCode_Success; | |
258 } | 237 } |
259 | 238 |
260 | 239 |
261 static void ConfigureFolders(const Json::Value& folders) | 240 static void ConfigureFolders(const Json::Value& folders) |
262 { | 241 { |
311 folders_[baseUri] = folder; | 290 folders_[baseUri] = folder; |
312 | 291 |
313 // Register the callback to serve the folder | 292 // Register the callback to serve the folder |
314 { | 293 { |
315 const std::string regex = "/(" + baseUri + ")/(.*)"; | 294 const std::string regex = "/(" + baseUri + ")/(.*)"; |
316 OrthancPluginRegisterRestCallback(context_, regex.c_str(), FolderCallback); | 295 OrthancPlugins::RegisterRestCallback<ServeFolder>(context_, regex.c_str(), true); |
317 } | 296 } |
318 } | 297 } |
319 } | 298 } |
320 | 299 |
321 | 300 |
341 bool tmp; | 320 bool tmp; |
342 | 321 |
343 if (configuration.LookupBooleanValue(tmp, "AllowCache")) | 322 if (configuration.LookupBooleanValue(tmp, "AllowCache")) |
344 { | 323 { |
345 allowCache_ = tmp; | 324 allowCache_ = tmp; |
346 OrthancPlugins::LogWarning(context_, "ServeFolders- Requesting the HTTP client to " + | 325 OrthancPlugins::LogWarning(context_, "ServeFolders: Requesting the HTTP client to " + |
347 std::string(allowCache_ ? "enable" : "disable") + | 326 std::string(tmp ? "enable" : "disable") + |
348 " its caching mechanism"); | 327 " its caching mechanism"); |
349 } | 328 } |
329 | |
330 if (configuration.LookupBooleanValue(tmp, "GenerateETag")) | |
331 { | |
332 generateETag_ = tmp; | |
333 OrthancPlugins::LogWarning(context_, "ServeFolders: The computation of an ETag for the served resources is " + | |
334 std::string(tmp ? "enabled" : "disabled")); | |
335 } | |
350 } | 336 } |
351 | 337 |
352 if (folders_.empty()) | 338 if (folders_.empty()) |
353 { | 339 { |
354 OrthancPlugins::LogWarning(context_, "ServeFolders- Empty configuration file: No additional folder will be served!"); | 340 OrthancPlugins::LogWarning(context_, "ServeFolders: Empty configuration file: No additional folder will be served!"); |
355 } | 341 } |
356 } | 342 } |
357 | 343 |
358 | 344 |
359 extern "C" | 345 extern "C" |
376 } | 362 } |
377 | 363 |
378 RegisterDefaultExtensions(); | 364 RegisterDefaultExtensions(); |
379 OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc."); | 365 OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc."); |
380 OrthancPluginSetRootUri(context, INDEX_URI); | 366 OrthancPluginSetRootUri(context, INDEX_URI); |
381 OrthancPluginRegisterRestCallback(context, INDEX_URI, ListServedFolders); | 367 OrthancPlugins::RegisterRestCallback<ListServedFolders>(context_, INDEX_URI, true); |
382 | 368 |
383 try | 369 try |
384 { | 370 { |
385 ReadConfiguration(); | 371 ReadConfiguration(); |
386 } | 372 } |