Mercurial > hg > orthanc
comparison OrthancFramework/Sources/RestApi/RestApi.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | Core/RestApi/RestApi.cpp@94f4a18a79cc |
children | bf7b9edf6b81 |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
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 | |
34 #include "../PrecompiledHeaders.h" | |
35 #include "RestApi.h" | |
36 | |
37 #include "../Logging.h" | |
38 | |
39 #include <stdlib.h> // To define "_exit()" under Windows | |
40 #include <stdio.h> | |
41 | |
42 namespace Orthanc | |
43 { | |
44 namespace | |
45 { | |
46 // Anonymous namespace to avoid clashes between compilation modules | |
47 class HttpHandlerVisitor : public RestApiHierarchy::IVisitor | |
48 { | |
49 private: | |
50 RestApi& api_; | |
51 RestApiOutput& output_; | |
52 RequestOrigin origin_; | |
53 const char* remoteIp_; | |
54 const char* username_; | |
55 HttpMethod method_; | |
56 const IHttpHandler::Arguments& headers_; | |
57 const IHttpHandler::Arguments& getArguments_; | |
58 const void* bodyData_; | |
59 size_t bodySize_; | |
60 | |
61 public: | |
62 HttpHandlerVisitor(RestApi& api, | |
63 RestApiOutput& output, | |
64 RequestOrigin origin, | |
65 const char* remoteIp, | |
66 const char* username, | |
67 HttpMethod method, | |
68 const IHttpHandler::Arguments& headers, | |
69 const IHttpHandler::Arguments& getArguments, | |
70 const void* bodyData, | |
71 size_t bodySize) : | |
72 api_(api), | |
73 output_(output), | |
74 origin_(origin), | |
75 remoteIp_(remoteIp), | |
76 username_(username), | |
77 method_(method), | |
78 headers_(headers), | |
79 getArguments_(getArguments), | |
80 bodyData_(bodyData), | |
81 bodySize_(bodySize) | |
82 { | |
83 } | |
84 | |
85 virtual bool Visit(const RestApiHierarchy::Resource& resource, | |
86 const UriComponents& uri, | |
87 const IHttpHandler::Arguments& components, | |
88 const UriComponents& trailing) | |
89 { | |
90 if (resource.HasHandler(method_)) | |
91 { | |
92 switch (method_) | |
93 { | |
94 case HttpMethod_Get: | |
95 { | |
96 RestApiGetCall call(output_, api_, origin_, remoteIp_, username_, | |
97 headers_, components, trailing, uri, getArguments_); | |
98 resource.Handle(call); | |
99 return true; | |
100 } | |
101 | |
102 case HttpMethod_Post: | |
103 { | |
104 RestApiPostCall call(output_, api_, origin_, remoteIp_, username_, | |
105 headers_, components, trailing, uri, bodyData_, bodySize_); | |
106 resource.Handle(call); | |
107 return true; | |
108 } | |
109 | |
110 case HttpMethod_Delete: | |
111 { | |
112 RestApiDeleteCall call(output_, api_, origin_, remoteIp_, username_, | |
113 headers_, components, trailing, uri); | |
114 resource.Handle(call); | |
115 return true; | |
116 } | |
117 | |
118 case HttpMethod_Put: | |
119 { | |
120 RestApiPutCall call(output_, api_, origin_, remoteIp_, username_, | |
121 headers_, components, trailing, uri, bodyData_, bodySize_); | |
122 resource.Handle(call); | |
123 return true; | |
124 } | |
125 | |
126 default: | |
127 return false; | |
128 } | |
129 } | |
130 | |
131 return false; | |
132 } | |
133 }; | |
134 } | |
135 | |
136 | |
137 | |
138 static void AddMethod(std::string& target, | |
139 const std::string& method) | |
140 { | |
141 if (target.size() > 0) | |
142 target += "," + method; | |
143 else | |
144 target = method; | |
145 } | |
146 | |
147 static std::string MethodsToString(const std::set<HttpMethod>& methods) | |
148 { | |
149 std::string s; | |
150 | |
151 if (methods.find(HttpMethod_Get) != methods.end()) | |
152 { | |
153 AddMethod(s, "GET"); | |
154 } | |
155 | |
156 if (methods.find(HttpMethod_Post) != methods.end()) | |
157 { | |
158 AddMethod(s, "POST"); | |
159 } | |
160 | |
161 if (methods.find(HttpMethod_Put) != methods.end()) | |
162 { | |
163 AddMethod(s, "PUT"); | |
164 } | |
165 | |
166 if (methods.find(HttpMethod_Delete) != methods.end()) | |
167 { | |
168 AddMethod(s, "DELETE"); | |
169 } | |
170 | |
171 return s; | |
172 } | |
173 | |
174 | |
175 | |
176 bool RestApi::Handle(HttpOutput& output, | |
177 RequestOrigin origin, | |
178 const char* remoteIp, | |
179 const char* username, | |
180 HttpMethod method, | |
181 const UriComponents& uri, | |
182 const Arguments& headers, | |
183 const GetArguments& getArguments, | |
184 const void* bodyData, | |
185 size_t bodySize) | |
186 { | |
187 RestApiOutput wrappedOutput(output, method); | |
188 | |
189 #if ORTHANC_ENABLE_PUGIXML == 1 | |
190 { | |
191 // Look if the client wishes XML answers instead of JSON | |
192 // http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3 | |
193 Arguments::const_iterator it = headers.find("accept"); | |
194 if (it != headers.end()) | |
195 { | |
196 std::vector<std::string> accepted; | |
197 Toolbox::TokenizeString(accepted, it->second, ';'); | |
198 for (size_t i = 0; i < accepted.size(); i++) | |
199 { | |
200 if (accepted[i] == MIME_XML) | |
201 { | |
202 wrappedOutput.SetConvertJsonToXml(true); | |
203 } | |
204 | |
205 if (accepted[i] == MIME_JSON) | |
206 { | |
207 wrappedOutput.SetConvertJsonToXml(false); | |
208 } | |
209 } | |
210 } | |
211 } | |
212 #endif | |
213 | |
214 Arguments compiled; | |
215 HttpToolbox::CompileGetArguments(compiled, getArguments); | |
216 | |
217 HttpHandlerVisitor visitor(*this, wrappedOutput, origin, remoteIp, username, | |
218 method, headers, compiled, bodyData, bodySize); | |
219 | |
220 if (root_.LookupResource(uri, visitor)) | |
221 { | |
222 wrappedOutput.Finalize(); | |
223 return true; | |
224 } | |
225 | |
226 std::set<HttpMethod> methods; | |
227 root_.GetAcceptedMethods(methods, uri); | |
228 | |
229 if (methods.empty()) | |
230 { | |
231 return false; // This URI is not served by this REST API | |
232 } | |
233 else | |
234 { | |
235 LOG(INFO) << "REST method " << EnumerationToString(method) | |
236 << " not allowed on: " << Toolbox::FlattenUri(uri); | |
237 | |
238 output.SendMethodNotAllowed(MethodsToString(methods)); | |
239 | |
240 return true; | |
241 } | |
242 } | |
243 | |
244 void RestApi::Register(const std::string& path, | |
245 RestApiGetCall::Handler handler) | |
246 { | |
247 root_.Register(path, handler); | |
248 } | |
249 | |
250 void RestApi::Register(const std::string& path, | |
251 RestApiPutCall::Handler handler) | |
252 { | |
253 root_.Register(path, handler); | |
254 } | |
255 | |
256 void RestApi::Register(const std::string& path, | |
257 RestApiPostCall::Handler handler) | |
258 { | |
259 root_.Register(path, handler); | |
260 } | |
261 | |
262 void RestApi::Register(const std::string& path, | |
263 RestApiDeleteCall::Handler handler) | |
264 { | |
265 root_.Register(path, handler); | |
266 } | |
267 | |
268 void RestApi::AutoListChildren(RestApiGetCall& call) | |
269 { | |
270 RestApi& context = call.GetContext(); | |
271 | |
272 Json::Value directory; | |
273 if (context.root_.GetDirectory(directory, call.GetFullUri())) | |
274 { | |
275 call.GetOutput().AnswerJson(directory); | |
276 } | |
277 } | |
278 } |