Mercurial > hg > orthanc
annotate Core/RestApi/RestApiHierarchy.cpp @ 2419:f51e9e852299
add tags
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 06 Oct 2017 17:26:15 +0200 |
parents | a3a65de1840f |
children | 878b59270859 |
rev | line source |
---|---|
969 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1063
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
2244
a3a65de1840f
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1900
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
969 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
1624
0a2ad4a6858f
fix missing precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1444
diff
changeset
|
34 #include "../PrecompiledHeaders.h" |
969 | 35 #include "RestApiHierarchy.h" |
36 | |
975 | 37 #include "../OrthancException.h" |
38 | |
969 | 39 #include <cassert> |
1063
0332e6e8c679
Fix automated generation of the list of resource children in the REST API
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
980
diff
changeset
|
40 #include <stdio.h> |
969 | 41 |
42 namespace Orthanc | |
43 { | |
978 | 44 RestApiHierarchy::Resource::Resource() : |
972 | 45 getHandler_(NULL), |
46 postHandler_(NULL), | |
47 putHandler_(NULL), | |
48 deleteHandler_(NULL) | |
49 { | |
50 } | |
51 | |
52 | |
978 | 53 bool RestApiHierarchy::Resource::HasHandler(HttpMethod method) const |
972 | 54 { |
55 switch (method) | |
56 { | |
57 case HttpMethod_Get: | |
58 return getHandler_ != NULL; | |
59 | |
60 case HttpMethod_Post: | |
61 return postHandler_ != NULL; | |
62 | |
63 case HttpMethod_Put: | |
64 return putHandler_ != NULL; | |
65 | |
66 case HttpMethod_Delete: | |
67 return deleteHandler_ != NULL; | |
68 | |
69 default: | |
70 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
71 } | |
72 } | |
73 | |
74 | |
978 | 75 bool RestApiHierarchy::Resource::IsEmpty() const |
969 | 76 { |
972 | 77 return (getHandler_ == NULL && |
78 postHandler_ == NULL && | |
79 putHandler_ == NULL && | |
80 deleteHandler_ == NULL); | |
81 } | |
82 | |
83 | |
969 | 84 RestApiHierarchy& RestApiHierarchy::AddChild(Children& children, |
85 const std::string& name) | |
86 { | |
87 Children::iterator it = children.find(name); | |
88 | |
89 if (it == children.end()) | |
90 { | |
91 // Create new child | |
92 RestApiHierarchy *child = new RestApiHierarchy; | |
93 children[name] = child; | |
94 return *child; | |
95 } | |
96 else | |
97 { | |
98 return *it->second; | |
99 } | |
100 } | |
101 | |
102 | |
978 | 103 |
104 bool RestApiHierarchy::Resource::Handle(RestApiGetCall& call) const | |
105 { | |
106 if (getHandler_ != NULL) | |
107 { | |
108 getHandler_(call); | |
109 return true; | |
110 } | |
111 else | |
112 { | |
113 return false; | |
114 } | |
115 } | |
116 | |
117 | |
118 bool RestApiHierarchy::Resource::Handle(RestApiPutCall& call) const | |
119 { | |
120 if (putHandler_ != NULL) | |
121 { | |
122 putHandler_(call); | |
123 return true; | |
124 } | |
125 else | |
126 { | |
127 return false; | |
128 } | |
129 } | |
130 | |
131 | |
132 bool RestApiHierarchy::Resource::Handle(RestApiPostCall& call) const | |
133 { | |
134 if (postHandler_ != NULL) | |
135 { | |
136 postHandler_(call); | |
137 return true; | |
138 } | |
139 else | |
140 { | |
141 return false; | |
142 } | |
143 } | |
144 | |
145 | |
146 bool RestApiHierarchy::Resource::Handle(RestApiDeleteCall& call) const | |
147 { | |
148 if (deleteHandler_ != NULL) | |
149 { | |
150 deleteHandler_(call); | |
151 return true; | |
152 } | |
153 else | |
154 { | |
155 return false; | |
156 } | |
157 } | |
158 | |
159 | |
160 | |
969 | 161 void RestApiHierarchy::DeleteChildren(Children& children) |
162 { | |
163 for (Children::iterator it = children.begin(); | |
1303 | 164 it != children.end(); ++it) |
969 | 165 { |
166 delete it->second; | |
167 } | |
168 } | |
169 | |
170 | |
171 template <typename Handler> | |
172 void RestApiHierarchy::RegisterInternal(const RestApiPath& path, | |
173 Handler handler, | |
174 size_t level) | |
175 { | |
176 if (path.GetLevelCount() == level) | |
177 { | |
178 if (path.IsUniversalTrailing()) | |
179 { | |
180 universalHandlers_.Register(handler); | |
181 } | |
182 else | |
183 { | |
184 handlers_.Register(handler); | |
185 } | |
186 } | |
187 else | |
188 { | |
189 RestApiHierarchy* child; | |
190 if (path.IsWildcardLevel(level)) | |
191 { | |
192 child = &AddChild(wildcardChildren_, path.GetWildcardName(level)); | |
193 } | |
194 else | |
195 { | |
196 child = &AddChild(children_, path.GetLevelName(level)); | |
197 } | |
198 | |
199 child->RegisterInternal(path, handler, level + 1); | |
200 } | |
201 } | |
202 | |
203 | |
1441
f3672356c121
refactoring: IHttpHandler and HttpToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1303
diff
changeset
|
204 bool RestApiHierarchy::LookupResource(IHttpHandler::Arguments& components, |
969 | 205 const UriComponents& uri, |
978 | 206 IVisitor& visitor, |
207 size_t level) | |
969 | 208 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
209 if (uri.size() != 0 && |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
210 level > uri.size()) |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
211 { |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
212 return false; |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
213 } |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
214 |
969 | 215 UriComponents trailing; |
216 | |
217 // Look for an exact match on the resource of interest | |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
218 if (uri.size() == 0 || |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
219 level == uri.size()) |
969 | 220 { |
221 if (!handlers_.IsEmpty() && | |
978 | 222 visitor.Visit(handlers_, uri, components, trailing)) |
969 | 223 { |
224 return true; | |
225 } | |
226 } | |
227 | |
228 | |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
229 if (level < uri.size()) // A recursive call is possible |
969 | 230 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
231 // Try and go down in the hierarchy, using an exact match for the child |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
232 Children::const_iterator child = children_.find(uri[level]); |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
233 if (child != children_.end()) |
969 | 234 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
235 if (child->second->LookupResource(components, uri, visitor, level + 1)) |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
236 { |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
237 return true; |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
238 } |
969 | 239 } |
240 | |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
241 // Try and go down in the hierarchy, using wildcard rules for children |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
242 for (child = wildcardChildren_.begin(); |
1303 | 243 child != wildcardChildren_.end(); ++child) |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
244 { |
1441
f3672356c121
refactoring: IHttpHandler and HttpToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1303
diff
changeset
|
245 IHttpHandler::Arguments subComponents = components; |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
246 subComponents[child->first] = uri[level]; |
969 | 247 |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
248 if (child->second->LookupResource(subComponents, uri, visitor, level + 1)) |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
249 { |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
250 return true; |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
251 } |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
252 } |
969 | 253 } |
254 | |
255 | |
256 // As a last resort, call the universal handlers, if any | |
257 if (!universalHandlers_.IsEmpty()) | |
258 { | |
259 trailing.resize(uri.size() - level); | |
260 size_t pos = 0; | |
261 for (size_t i = level; i < uri.size(); i++, pos++) | |
262 { | |
263 trailing[pos] = uri[i]; | |
264 } | |
265 | |
266 assert(pos == trailing.size()); | |
267 | |
978 | 268 if (visitor.Visit(universalHandlers_, uri, components, trailing)) |
969 | 269 { |
270 return true; | |
271 } | |
272 } | |
273 | |
274 return false; | |
275 } | |
276 | |
277 | |
978 | 278 bool RestApiHierarchy::CanGenerateDirectory() const |
279 { | |
1063
0332e6e8c679
Fix automated generation of the list of resource children in the REST API
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
980
diff
changeset
|
280 return (universalHandlers_.IsEmpty() && |
1303 | 281 wildcardChildren_.empty()); |
978 | 282 } |
283 | |
284 | |
969 | 285 bool RestApiHierarchy::GetDirectory(Json::Value& result, |
286 const UriComponents& uri, | |
287 size_t level) | |
288 { | |
289 if (uri.size() == level) | |
290 { | |
978 | 291 if (CanGenerateDirectory()) |
969 | 292 { |
293 result = Json::arrayValue; | |
294 | |
295 for (Children::const_iterator it = children_.begin(); | |
1303 | 296 it != children_.end(); ++it) |
969 | 297 { |
298 result.append(it->first); | |
299 } | |
300 | |
301 return true; | |
302 } | |
303 else | |
304 { | |
305 return false; | |
306 } | |
307 } | |
308 | |
309 Children::const_iterator child = children_.find(uri[level]); | |
310 if (child != children_.end()) | |
311 { | |
312 if (child->second->GetDirectory(result, uri, level + 1)) | |
313 { | |
314 return true; | |
315 } | |
316 } | |
317 | |
318 for (child = wildcardChildren_.begin(); | |
1303 | 319 child != wildcardChildren_.end(); ++child) |
969 | 320 { |
321 if (child->second->GetDirectory(result, uri, level + 1)) | |
322 { | |
323 return true; | |
324 } | |
325 } | |
326 | |
327 return false; | |
328 } | |
329 | |
330 | |
331 RestApiHierarchy::~RestApiHierarchy() | |
332 { | |
333 DeleteChildren(children_); | |
334 DeleteChildren(wildcardChildren_); | |
335 } | |
336 | |
970 | 337 void RestApiHierarchy::Register(const std::string& uri, |
974 | 338 RestApiGetCall::Handler handler) |
969 | 339 { |
970 | 340 RestApiPath path(uri); |
969 | 341 RegisterInternal(path, handler, 0); |
342 } | |
343 | |
970 | 344 void RestApiHierarchy::Register(const std::string& uri, |
974 | 345 RestApiPutCall::Handler handler) |
969 | 346 { |
970 | 347 RestApiPath path(uri); |
969 | 348 RegisterInternal(path, handler, 0); |
349 } | |
350 | |
970 | 351 void RestApiHierarchy::Register(const std::string& uri, |
974 | 352 RestApiPostCall::Handler handler) |
969 | 353 { |
970 | 354 RestApiPath path(uri); |
969 | 355 RegisterInternal(path, handler, 0); |
356 } | |
357 | |
970 | 358 void RestApiHierarchy::Register(const std::string& uri, |
974 | 359 RestApiDeleteCall::Handler handler) |
969 | 360 { |
970 | 361 RestApiPath path(uri); |
969 | 362 RegisterInternal(path, handler, 0); |
363 } | |
364 | |
365 void RestApiHierarchy::CreateSiteMap(Json::Value& target) const | |
366 { | |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
367 target = Json::objectValue; |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
368 |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
369 /*std::string s = " "; |
972 | 370 if (handlers_.HasHandler(HttpMethod_Get)) |
969 | 371 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
372 s += "GET "; |
969 | 373 } |
374 | |
972 | 375 if (handlers_.HasHandler(HttpMethod_Post)) |
969 | 376 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
377 s += "POST "; |
969 | 378 } |
379 | |
972 | 380 if (handlers_.HasHandler(HttpMethod_Put)) |
969 | 381 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
382 s += "PUT "; |
969 | 383 } |
384 | |
972 | 385 if (handlers_.HasHandler(HttpMethod_Delete)) |
969 | 386 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
387 s += "DELETE "; |
969 | 388 } |
389 | |
978 | 390 target = s;*/ |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
391 |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
392 for (Children::const_iterator it = children_.begin(); |
1303 | 393 it != children_.end(); ++it) |
969 | 394 { |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
395 it->second->CreateSiteMap(target[it->first]); |
969 | 396 } |
397 | |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
398 for (Children::const_iterator it = wildcardChildren_.begin(); |
1303 | 399 it != wildcardChildren_.end(); ++it) |
980
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
400 { |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
401 it->second->CreateSiteMap(target["<" + it->first + ">"]); |
f1ff2a2f06cd
use RestApiHierarchy inside RestApi
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
978
diff
changeset
|
402 } |
969 | 403 } |
404 | |
978 | 405 |
406 bool RestApiHierarchy::LookupResource(const UriComponents& uri, | |
407 IVisitor& visitor) | |
969 | 408 { |
1441
f3672356c121
refactoring: IHttpHandler and HttpToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1303
diff
changeset
|
409 IHttpHandler::Arguments components; |
978 | 410 return LookupResource(components, uri, visitor, 0); |
969 | 411 } |
412 | |
978 | 413 |
414 | |
415 namespace | |
416 { | |
417 // Anonymous namespace to avoid clashes between compilation modules | |
418 | |
419 class AcceptedMethodsVisitor : public RestApiHierarchy::IVisitor | |
420 { | |
421 private: | |
422 std::set<HttpMethod>& methods_; | |
423 | |
424 public: | |
425 AcceptedMethodsVisitor(std::set<HttpMethod>& methods) : methods_(methods) | |
426 { | |
427 } | |
428 | |
429 virtual bool Visit(const RestApiHierarchy::Resource& resource, | |
430 const UriComponents& uri, | |
1441
f3672356c121
refactoring: IHttpHandler and HttpToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1303
diff
changeset
|
431 const IHttpHandler::Arguments& components, |
978 | 432 const UriComponents& trailing) |
433 { | |
434 if (trailing.size() == 0) // Ignore universal handlers | |
435 { | |
436 if (resource.HasHandler(HttpMethod_Get)) | |
437 { | |
438 methods_.insert(HttpMethod_Get); | |
439 } | |
440 | |
441 if (resource.HasHandler(HttpMethod_Post)) | |
442 { | |
443 methods_.insert(HttpMethod_Post); | |
444 } | |
445 | |
446 if (resource.HasHandler(HttpMethod_Put)) | |
447 { | |
448 methods_.insert(HttpMethod_Put); | |
449 } | |
450 | |
451 if (resource.HasHandler(HttpMethod_Delete)) | |
452 { | |
453 methods_.insert(HttpMethod_Delete); | |
454 } | |
455 } | |
456 | |
457 return false; // Continue to check all the possible ways to access this URI | |
458 } | |
459 }; | |
460 } | |
461 | |
462 void RestApiHierarchy::GetAcceptedMethods(std::set<HttpMethod>& methods, | |
463 const UriComponents& uri) | |
969 | 464 { |
1441
f3672356c121
refactoring: IHttpHandler and HttpToolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1303
diff
changeset
|
465 IHttpHandler::Arguments components; |
978 | 466 AcceptedMethodsVisitor visitor(methods); |
1444
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
467 if (LookupResource(components, uri, visitor, 0)) |
978 | 468 { |
1444
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
469 Json::Value d; |
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
470 if (GetDirectory(d, uri)) |
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
471 { |
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
472 methods.insert(HttpMethod_Get); |
b2b09a3dbd8e
refactoring: OrthancHttpHandler inside OrthancServer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1441
diff
changeset
|
473 } |
978 | 474 } |
475 } | |
969 | 476 } |