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 }