comparison OrthancFramework/Sources/HttpServer/HttpToolbox.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/HttpServer/HttpToolbox.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 "HttpToolbox.h"
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <iostream>
40
41 #include "HttpOutput.h"
42 #include "StringHttpOutput.h"
43
44
45 static const char* LOCALHOST = "127.0.0.1";
46
47
48
49 namespace Orthanc
50 {
51 static void SplitGETNameValue(IHttpHandler::GetArguments& result,
52 const char* start,
53 const char* end)
54 {
55 std::string name, value;
56
57 const char* equal = strchr(start, '=');
58 if (equal == NULL || equal >= end)
59 {
60 name = std::string(start, end - start);
61 //value = "";
62 }
63 else
64 {
65 name = std::string(start, equal - start);
66 value = std::string(equal + 1, end);
67 }
68
69 Toolbox::UrlDecode(name);
70 Toolbox::UrlDecode(value);
71
72 result.push_back(std::make_pair(name, value));
73 }
74
75
76 void HttpToolbox::ParseGetArguments(IHttpHandler::GetArguments& result,
77 const char* query)
78 {
79 const char* pos = query;
80
81 while (pos != NULL)
82 {
83 const char* ampersand = strchr(pos, '&');
84 if (ampersand)
85 {
86 SplitGETNameValue(result, pos, ampersand);
87 pos = ampersand + 1;
88 }
89 else
90 {
91 // No more ampersand, this is the last argument
92 SplitGETNameValue(result, pos, pos + strlen(pos));
93 pos = NULL;
94 }
95 }
96 }
97
98
99 void HttpToolbox::ParseGetQuery(UriComponents& uri,
100 IHttpHandler::GetArguments& getArguments,
101 const char* query)
102 {
103 const char *questionMark = ::strchr(query, '?');
104 if (questionMark == NULL)
105 {
106 // No question mark in the string
107 Toolbox::SplitUriComponents(uri, query);
108 getArguments.clear();
109 }
110 else
111 {
112 Toolbox::SplitUriComponents(uri, std::string(query, questionMark));
113 HttpToolbox::ParseGetArguments(getArguments, questionMark + 1);
114 }
115 }
116
117
118 std::string HttpToolbox::GetArgument(const IHttpHandler::Arguments& getArguments,
119 const std::string& name,
120 const std::string& defaultValue)
121 {
122 IHttpHandler::Arguments::const_iterator it = getArguments.find(name);
123 if (it == getArguments.end())
124 {
125 return defaultValue;
126 }
127 else
128 {
129 return it->second;
130 }
131 }
132
133
134 std::string HttpToolbox::GetArgument(const IHttpHandler::GetArguments& getArguments,
135 const std::string& name,
136 const std::string& defaultValue)
137 {
138 for (size_t i = 0; i < getArguments.size(); i++)
139 {
140 if (getArguments[i].first == name)
141 {
142 return getArguments[i].second;
143 }
144 }
145
146 return defaultValue;
147 }
148
149
150
151 void HttpToolbox::ParseCookies(IHttpHandler::Arguments& result,
152 const IHttpHandler::Arguments& httpHeaders)
153 {
154 result.clear();
155
156 IHttpHandler::Arguments::const_iterator it = httpHeaders.find("cookie");
157 if (it != httpHeaders.end())
158 {
159 const std::string& cookies = it->second;
160
161 size_t pos = 0;
162 while (pos != std::string::npos)
163 {
164 size_t nextSemicolon = cookies.find(";", pos);
165 std::string cookie;
166
167 if (nextSemicolon == std::string::npos)
168 {
169 cookie = cookies.substr(pos);
170 pos = std::string::npos;
171 }
172 else
173 {
174 cookie = cookies.substr(pos, nextSemicolon - pos);
175 pos = nextSemicolon + 1;
176 }
177
178 size_t equal = cookie.find("=");
179 if (equal != std::string::npos)
180 {
181 std::string name = Toolbox::StripSpaces(cookie.substr(0, equal));
182 std::string value = Toolbox::StripSpaces(cookie.substr(equal + 1));
183 result[name] = value;
184 }
185 }
186 }
187 }
188
189
190 void HttpToolbox::CompileGetArguments(IHttpHandler::Arguments& compiled,
191 const IHttpHandler::GetArguments& source)
192 {
193 compiled.clear();
194
195 for (size_t i = 0; i < source.size(); i++)
196 {
197 compiled[source[i].first] = source[i].second;
198 }
199 }
200
201
202 bool HttpToolbox::SimpleGet(std::string& result,
203 IHttpHandler& handler,
204 RequestOrigin origin,
205 const std::string& uri,
206 const IHttpHandler::Arguments& httpHeaders)
207 {
208 UriComponents curi;
209 IHttpHandler::GetArguments getArguments;
210 ParseGetQuery(curi, getArguments, uri.c_str());
211
212 StringHttpOutput stream;
213 HttpOutput http(stream, false /* no keep alive */);
214
215 if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Get, curi,
216 httpHeaders, getArguments, NULL /* no body for GET */, 0))
217 {
218 stream.GetOutput(result);
219 return true;
220 }
221 else
222 {
223 return false;
224 }
225 }
226
227
228 static bool SimplePostOrPut(std::string& result,
229 IHttpHandler& handler,
230 RequestOrigin origin,
231 HttpMethod method,
232 const std::string& uri,
233 const void* bodyData,
234 size_t bodySize,
235 const IHttpHandler::Arguments& httpHeaders)
236 {
237 IHttpHandler::GetArguments getArguments; // No GET argument for POST/PUT
238
239 UriComponents curi;
240 Toolbox::SplitUriComponents(curi, uri);
241
242 StringHttpOutput stream;
243 HttpOutput http(stream, false /* no keep alive */);
244
245 if (handler.Handle(http, origin, LOCALHOST, "", method, curi,
246 httpHeaders, getArguments, bodyData, bodySize))
247 {
248 stream.GetOutput(result);
249 return true;
250 }
251 else
252 {
253 return false;
254 }
255 }
256
257
258 bool HttpToolbox::SimplePost(std::string& result,
259 IHttpHandler& handler,
260 RequestOrigin origin,
261 const std::string& uri,
262 const void* bodyData,
263 size_t bodySize,
264 const IHttpHandler::Arguments& httpHeaders)
265 {
266 return SimplePostOrPut(result, handler, origin, HttpMethod_Post, uri, bodyData, bodySize, httpHeaders);
267 }
268
269
270 bool HttpToolbox::SimplePut(std::string& result,
271 IHttpHandler& handler,
272 RequestOrigin origin,
273 const std::string& uri,
274 const void* bodyData,
275 size_t bodySize,
276 const IHttpHandler::Arguments& httpHeaders)
277 {
278 return SimplePostOrPut(result, handler, origin, HttpMethod_Put, uri, bodyData, bodySize, httpHeaders);
279 }
280
281
282 bool HttpToolbox::SimpleDelete(IHttpHandler& handler,
283 RequestOrigin origin,
284 const std::string& uri,
285 const IHttpHandler::Arguments& httpHeaders)
286 {
287 UriComponents curi;
288 Toolbox::SplitUriComponents(curi, uri);
289
290 IHttpHandler::GetArguments getArguments; // No GET argument for DELETE
291
292 StringHttpOutput stream;
293 HttpOutput http(stream, false /* no keep alive */);
294
295 return handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi,
296 httpHeaders, getArguments, NULL /* no body for DELETE */, 0);
297 }
298 }