Mercurial > hg > orthanc
annotate Core/HttpServer/MongooseServer.cpp @ 207:7f74209ea0f8
RestApi
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 28 Nov 2012 16:23:11 +0100 |
parents | 93e1b0e3b83a |
children | 1ac3aacd10a5 |
rev | line source |
---|---|
0 | 1 /** |
59 | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
0 | 3 * Copyright (C) 2012 Medical Physics Department, CHU of Liege, |
4 * Belgium | |
5 * | |
6 * This program is free software: you can redistribute it and/or | |
7 * modify it under the terms of the GNU General Public License as | |
8 * published by the Free Software Foundation, either version 3 of the | |
9 * License, or (at your option) any later version. | |
136 | 10 * |
11 * In addition, as a special exception, the copyright holders of this | |
12 * program give permission to link the code of its release with the | |
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
14 * that use the same license as the "OpenSSL" library), and distribute | |
15 * the linked executables. You must obey the GNU General Public License | |
16 * in all respects for all of the code used other than "OpenSSL". If you | |
17 * modify file(s) with this exception, you may extend this exception to | |
18 * your version of the file(s), but you are not obligated to do so. If | |
19 * you do not wish to do so, delete this exception statement from your | |
20 * version. If you delete this exception statement from all source files | |
21 * in the program, then also delete it here. | |
0 | 22 * |
23 * This program is distributed in the hope that it will be useful, but | |
24 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 * General Public License for more details. | |
27 * | |
28 * You should have received a copy of the GNU General Public License | |
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
30 **/ | |
31 | |
32 | |
33 // http://en.highscore.de/cpp/boost/stringhandling.html | |
34 | |
35 #include "MongooseServer.h" | |
36 | |
37 #include <algorithm> | |
38 #include <string.h> | |
39 #include <boost/lexical_cast.hpp> | |
40 #include <boost/algorithm/string.hpp> | |
41 #include <iostream> | |
42 #include <string.h> | |
43 #include <stdio.h> | |
44 #include <boost/thread.hpp> | |
108 | 45 #include <glog/logging.h> |
0 | 46 |
59 | 47 #include "../OrthancException.h" |
0 | 48 #include "../ChunkedBuffer.h" |
49 #include "mongoose.h" | |
50 | |
51 | |
59 | 52 #define ORTHANC_REALM "Orthanc Secure Area" |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
53 |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
54 static const long LOCALHOST = (127ll << 24) + 1ll; |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
55 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
56 |
59 | 57 namespace Orthanc |
0 | 58 { |
59 static const char multipart[] = "multipart/form-data; boundary="; | |
60 static unsigned int multipartLength = sizeof(multipart) / sizeof(char) - 1; | |
61 | |
62 | |
63 namespace | |
64 { | |
65 // Anonymous namespace to avoid clashes between compilation modules | |
66 class MongooseOutput : public HttpOutput | |
67 { | |
68 private: | |
69 struct mg_connection* connection_; | |
70 | |
71 public: | |
72 MongooseOutput(struct mg_connection* connection) : connection_(connection) | |
73 { | |
74 } | |
75 | |
76 virtual void Send(const void* buffer, size_t length) | |
77 { | |
78 mg_write(connection_, buffer, length); | |
79 } | |
80 }; | |
81 | |
82 | |
83 enum PostDataStatus | |
84 { | |
85 PostDataStatus_Success, | |
86 PostDataStatus_NoLength, | |
87 PostDataStatus_Pending, | |
88 PostDataStatus_Failure | |
89 }; | |
90 } | |
91 | |
92 | |
93 // TODO Move this to external file | |
94 | |
95 | |
96 class ChunkedFile : public ChunkedBuffer | |
97 { | |
98 private: | |
99 std::string filename_; | |
100 | |
101 public: | |
102 ChunkedFile(const std::string& filename) : | |
103 filename_(filename) | |
104 { | |
105 } | |
106 | |
107 const std::string& GetFilename() const | |
108 { | |
109 return filename_; | |
110 } | |
111 }; | |
112 | |
113 | |
114 | |
115 class ChunkStore | |
116 { | |
117 private: | |
118 typedef std::list<ChunkedFile*> Content; | |
119 Content content_; | |
120 unsigned int numPlaces_; | |
121 | |
122 boost::mutex mutex_; | |
123 std::set<std::string> discardedFiles_; | |
124 | |
125 void Clear() | |
126 { | |
127 for (Content::iterator it = content_.begin(); | |
128 it != content_.end(); it++) | |
129 { | |
130 delete *it; | |
131 } | |
132 } | |
133 | |
134 Content::iterator Find(const std::string& filename) | |
135 { | |
136 for (Content::iterator it = content_.begin(); | |
137 it != content_.end(); it++) | |
138 { | |
139 if ((*it)->GetFilename() == filename) | |
140 { | |
141 return it; | |
142 } | |
143 } | |
144 | |
145 return content_.end(); | |
146 } | |
147 | |
148 void Remove(const std::string& filename) | |
149 { | |
150 Content::iterator it = Find(filename); | |
151 if (it != content_.end()) | |
152 { | |
153 delete *it; | |
154 content_.erase(it); | |
155 } | |
156 } | |
157 | |
158 public: | |
159 ChunkStore() | |
160 { | |
161 numPlaces_ = 10; | |
162 } | |
163 | |
164 ~ChunkStore() | |
165 { | |
166 Clear(); | |
167 } | |
168 | |
169 PostDataStatus Store(std::string& completed, | |
170 const char* chunkData, | |
171 size_t chunkSize, | |
172 const std::string& filename, | |
173 size_t filesize) | |
174 { | |
175 boost::mutex::scoped_lock lock(mutex_); | |
176 | |
177 std::set<std::string>::iterator wasDiscarded = discardedFiles_.find(filename); | |
178 if (wasDiscarded != discardedFiles_.end()) | |
179 { | |
180 discardedFiles_.erase(wasDiscarded); | |
181 return PostDataStatus_Failure; | |
182 } | |
183 | |
184 ChunkedFile* f; | |
185 Content::iterator it = Find(filename); | |
186 if (it == content_.end()) | |
187 { | |
188 f = new ChunkedFile(filename); | |
189 | |
190 // Make some room | |
191 if (content_.size() >= numPlaces_) | |
192 { | |
193 discardedFiles_.insert(content_.front()->GetFilename()); | |
194 delete content_.front(); | |
195 content_.pop_front(); | |
196 } | |
197 | |
198 content_.push_back(f); | |
199 } | |
200 else | |
201 { | |
202 f = *it; | |
203 } | |
204 | |
205 f->AddChunk(chunkData, chunkSize); | |
206 | |
207 if (f->GetNumBytes() > filesize) | |
208 { | |
209 Remove(filename); | |
210 } | |
211 else if (f->GetNumBytes() == filesize) | |
212 { | |
213 f->Flatten(completed); | |
214 Remove(filename); | |
215 return PostDataStatus_Success; | |
216 } | |
217 | |
218 return PostDataStatus_Pending; | |
219 } | |
220 | |
221 /*void Print() | |
222 { | |
223 boost::mutex::scoped_lock lock(mutex_); | |
224 | |
225 printf("ChunkStore status:\n"); | |
226 for (Content::const_iterator i = content_.begin(); | |
227 i != content_.end(); i++) | |
228 { | |
229 printf(" [%s]: %d\n", (*i)->GetFilename().c_str(), (*i)->GetNumBytes()); | |
230 } | |
231 printf("-----\n"); | |
232 }*/ | |
233 }; | |
234 | |
235 | |
236 struct MongooseServer::PImpl | |
237 { | |
238 struct mg_context *context_; | |
239 ChunkStore chunkStore_; | |
240 }; | |
241 | |
242 | |
243 ChunkStore& MongooseServer::GetChunkStore() | |
244 { | |
245 return pimpl_->chunkStore_; | |
246 } | |
247 | |
248 | |
249 | |
250 HttpHandler* MongooseServer::FindHandler(const UriComponents& forUri) const | |
251 { | |
252 for (Handlers::const_iterator it = | |
253 handlers_.begin(); it != handlers_.end(); it++) | |
254 { | |
255 if ((*it)->IsServedUri(forUri)) | |
256 { | |
257 return *it; | |
258 } | |
259 } | |
260 | |
261 return NULL; | |
262 } | |
263 | |
264 | |
265 | |
266 | |
267 static PostDataStatus ReadPostData(std::string& postData, | |
268 struct mg_connection *connection, | |
269 const HttpHandler::Arguments& headers) | |
270 { | |
271 HttpHandler::Arguments::const_iterator cs = headers.find("content-length"); | |
272 if (cs == headers.end()) | |
273 { | |
274 return PostDataStatus_NoLength; | |
275 } | |
276 | |
277 int length; | |
278 try | |
279 { | |
280 length = boost::lexical_cast<int>(cs->second); | |
281 } | |
282 catch (boost::bad_lexical_cast) | |
283 { | |
284 return PostDataStatus_NoLength; | |
285 } | |
286 | |
287 if (length < 0) | |
288 { | |
289 length = 0; | |
290 } | |
291 | |
292 postData.resize(length); | |
293 | |
294 size_t pos = 0; | |
295 while (length > 0) | |
296 { | |
297 int r = mg_read(connection, &postData[pos], length); | |
298 if (r <= 0) | |
299 { | |
300 return PostDataStatus_Failure; | |
301 } | |
8 | 302 assert(r <= length); |
0 | 303 length -= r; |
304 pos += r; | |
305 } | |
306 | |
307 return PostDataStatus_Success; | |
308 } | |
309 | |
310 | |
311 | |
312 static PostDataStatus ParseMultipartPost(std::string &completedFile, | |
313 struct mg_connection *connection, | |
314 const HttpHandler::Arguments& headers, | |
315 const std::string& contentType, | |
316 ChunkStore& chunkStore) | |
317 { | |
318 std::string boundary = "--" + contentType.substr(multipartLength); | |
319 | |
320 std::string postData; | |
321 PostDataStatus status = ReadPostData(postData, connection, headers); | |
322 | |
323 if (status != PostDataStatus_Success) | |
324 { | |
325 return status; | |
326 } | |
327 | |
328 /*for (HttpHandler::Arguments::const_iterator i = headers.begin(); i != headers.end(); i++) | |
329 { | |
330 std::cout << "Header [" << i->first << "] = " << i->second << "\n"; | |
331 } | |
332 printf("CHUNK\n");*/ | |
333 | |
334 typedef HttpHandler::Arguments::const_iterator ArgumentIterator; | |
335 | |
336 ArgumentIterator requestedWith = headers.find("x-requested-with"); | |
337 ArgumentIterator fileName = headers.find("x-file-name"); | |
338 ArgumentIterator fileSizeStr = headers.find("x-file-size"); | |
339 | |
340 if (requestedWith == headers.end() || | |
341 requestedWith->second != "XMLHttpRequest") | |
342 { | |
343 return PostDataStatus_Failure; | |
344 } | |
345 | |
346 size_t fileSize = 0; | |
347 if (fileSizeStr != headers.end()) | |
348 { | |
349 try | |
350 { | |
351 fileSize = boost::lexical_cast<size_t>(fileSizeStr->second); | |
352 } | |
353 catch (boost::bad_lexical_cast) | |
354 { | |
355 return PostDataStatus_Failure; | |
356 } | |
357 } | |
358 | |
359 typedef boost::find_iterator<std::string::iterator> FindIterator; | |
10 | 360 typedef boost::iterator_range<char*> Range; |
0 | 361 |
362 //chunkStore.Print(); | |
363 | |
364 try | |
365 { | |
366 FindIterator last; | |
367 for (FindIterator it = | |
368 make_find_iterator(postData, boost::first_finder(boundary)); | |
369 it!=FindIterator(); | |
370 ++it) | |
371 { | |
372 if (last != FindIterator()) | |
373 { | |
10 | 374 Range part(&last->back(), &it->front()); |
0 | 375 Range content = boost::find_first(part, "\r\n\r\n"); |
376 if (content != Range()) | |
377 { | |
378 Range c(&content.back() + 1, &it->front() - 2); | |
379 size_t chunkSize = c.size(); | |
380 | |
381 if (chunkSize > 0) | |
382 { | |
383 const char* chunkData = &c.front(); | |
384 | |
385 if (fileName == headers.end()) | |
386 { | |
387 // This file is stored in a single chunk | |
388 completedFile.resize(chunkSize); | |
389 if (chunkSize > 0) | |
390 { | |
391 memcpy(&completedFile[0], chunkData, chunkSize); | |
392 } | |
393 return PostDataStatus_Success; | |
394 } | |
395 else | |
396 { | |
397 return chunkStore.Store(completedFile, chunkData, chunkSize, fileName->second, fileSize); | |
398 } | |
399 } | |
10 | 400 } |
0 | 401 } |
402 | |
403 last = it; | |
404 } | |
405 } | |
406 catch (std::length_error) | |
407 { | |
408 return PostDataStatus_Failure; | |
409 } | |
410 | |
411 return PostDataStatus_Pending; | |
412 } | |
413 | |
414 | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
415 static void SendUnauthorized(HttpOutput& output) |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
416 { |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
417 std::string s = "HTTP/1.1 401 Unauthorized\r\n" |
59 | 418 "WWW-Authenticate: Basic realm=\"" ORTHANC_REALM "\"" |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
419 "\r\n\r\n"; |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
420 output.Send(&s[0], s.size()); |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
421 } |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
422 |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
423 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
424 static bool Authorize(const MongooseServer& that, |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
425 const HttpHandler::Arguments& headers, |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
426 HttpOutput& output) |
23 | 427 { |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
428 bool granted = false; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
429 |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
430 HttpHandler::Arguments::const_iterator auth = headers.find("authorization"); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
431 if (auth != headers.end()) |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
432 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
433 std::string s = auth->second; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
434 if (s.substr(0, 6) == "Basic ") |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
435 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
436 std::string b64 = s.substr(6); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
437 granted = that.IsValidBasicHttpAuthentication(b64); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
438 } |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
439 } |
23 | 440 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
441 if (!granted) |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
442 { |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
443 SendUnauthorized(output); |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
444 return false; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
445 } |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
446 else |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
447 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
448 return true; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
449 } |
23 | 450 } |
451 | |
452 | |
0 | 453 |
454 static void* Callback(enum mg_event event, | |
455 struct mg_connection *connection, | |
456 const struct mg_request_info *request) | |
457 { | |
458 if (event == MG_NEW_REQUEST) | |
459 { | |
460 MongooseServer* that = (MongooseServer*) (request->user_data); | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
461 MongooseOutput output(connection); |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
462 |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
463 if (!that->IsRemoteAccessAllowed() && |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
464 request->remote_ip != LOCALHOST) |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
465 { |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
466 SendUnauthorized(output); |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
467 return (void*) ""; |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
468 } |
0 | 469 |
470 HttpHandler::Arguments arguments, headers; | |
471 | |
472 for (int i = 0; i < request->num_headers; i++) | |
473 { | |
474 std::string name = request->http_headers[i].name; | |
475 std::transform(name.begin(), name.end(), name.begin(), ::tolower); | |
476 headers.insert(std::make_pair(name, request->http_headers[i].value)); | |
477 } | |
478 | |
23 | 479 // Authenticate this connection |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
480 if (that->IsAuthenticationEnabled() && |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
481 !Authorize(*that, headers, output)) |
23 | 482 { |
483 return (void*) ""; | |
484 } | |
485 | |
0 | 486 std::string postData; |
487 | |
488 if (!strcmp(request->request_method, "GET")) | |
489 { | |
490 HttpHandler::ParseGetQuery(arguments, request->query_string); | |
491 } | |
207 | 492 else if (!strcmp(request->request_method, "POST") || |
493 !strcmp(request->request_method, "PUT")) | |
0 | 494 { |
495 HttpHandler::Arguments::const_iterator ct = headers.find("content-type"); | |
496 if (ct == headers.end()) | |
497 { | |
59 | 498 output.SendHeader(Orthanc_HttpStatus_400_BadRequest); |
0 | 499 return (void*) ""; |
500 } | |
501 | |
502 PostDataStatus status; | |
503 | |
504 std::string contentType = ct->second; | |
505 if (contentType.size() >= multipartLength && | |
506 !memcmp(contentType.c_str(), multipart, multipartLength)) | |
507 { | |
508 status = ParseMultipartPost(postData, connection, headers, contentType, that->GetChunkStore()); | |
509 } | |
510 else | |
511 { | |
512 status = ReadPostData(postData, connection, headers); | |
513 } | |
514 | |
515 switch (status) | |
516 { | |
517 case PostDataStatus_NoLength: | |
59 | 518 output.SendHeader(Orthanc_HttpStatus_411_LengthRequired); |
0 | 519 return (void*) ""; |
520 | |
521 case PostDataStatus_Failure: | |
59 | 522 output.SendHeader(Orthanc_HttpStatus_400_BadRequest); |
0 | 523 return (void*) ""; |
524 | |
525 case PostDataStatus_Pending: | |
155
93e1b0e3b83a
filenames when downloading json/dicom
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
136
diff
changeset
|
526 output.AnswerBufferWithContentType(NULL, 0, ""); |
0 | 527 return (void*) ""; |
528 | |
529 default: | |
530 break; | |
531 } | |
532 } | |
533 | |
534 UriComponents uri; | |
535 Toolbox::SplitUriComponents(uri, request->uri); | |
536 | |
537 HttpHandler* handler = that->FindHandler(uri); | |
538 if (handler) | |
539 { | |
540 try | |
541 { | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
542 handler->Handle(output, std::string(request->request_method), |
0 | 543 uri, headers, arguments, postData); |
544 } | |
59 | 545 catch (OrthancException& e) |
0 | 546 { |
108 | 547 LOG(ERROR) << "MongooseServer Exception [" << e.What() << "]"; |
59 | 548 output.SendHeader(Orthanc_HttpStatus_500_InternalServerError); |
0 | 549 } |
550 } | |
551 else | |
552 { | |
59 | 553 output.SendHeader(Orthanc_HttpStatus_404_NotFound); |
0 | 554 } |
555 | |
556 // Mark as processed | |
557 return (void*) ""; | |
558 } | |
559 else | |
560 { | |
561 return NULL; | |
562 } | |
563 } | |
564 | |
565 | |
566 bool MongooseServer::IsRunning() const | |
567 { | |
568 return (pimpl_->context_ != NULL); | |
569 } | |
570 | |
571 | |
572 MongooseServer::MongooseServer() : pimpl_(new PImpl) | |
573 { | |
574 pimpl_->context_ = NULL; | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
575 remoteAllowed_ = false; |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
576 authentication_ = false; |
23 | 577 ssl_ = false; |
0 | 578 port_ = 8000; |
579 } | |
580 | |
581 | |
582 MongooseServer::~MongooseServer() | |
583 { | |
584 Stop(); | |
585 ClearHandlers(); | |
586 } | |
587 | |
588 | |
128 | 589 void MongooseServer::SetPortNumber(uint16_t port) |
0 | 590 { |
591 Stop(); | |
592 port_ = port; | |
593 } | |
594 | |
595 void MongooseServer::Start() | |
596 { | |
597 if (!IsRunning()) | |
598 { | |
599 std::string port = boost::lexical_cast<std::string>(port_); | |
600 | |
23 | 601 if (ssl_) |
602 { | |
603 port += "s"; | |
604 } | |
605 | |
0 | 606 const char *options[] = { |
607 "listening_ports", port.c_str(), | |
23 | 608 ssl_ ? "ssl_certificate" : NULL, |
609 certificate_.c_str(), | |
0 | 610 NULL |
611 }; | |
612 | |
613 pimpl_->context_ = mg_start(&Callback, this, options); | |
614 if (!pimpl_->context_) | |
615 { | |
59 | 616 throw OrthancException("Unable to launch the Mongoose server"); |
0 | 617 } |
618 } | |
619 } | |
620 | |
621 void MongooseServer::Stop() | |
622 { | |
623 if (IsRunning()) | |
624 { | |
625 mg_stop(pimpl_->context_); | |
626 pimpl_->context_ = NULL; | |
627 } | |
628 } | |
629 | |
630 | |
631 void MongooseServer::RegisterHandler(HttpHandler* handler) | |
632 { | |
633 Stop(); | |
634 | |
635 handlers_.push_back(handler); | |
636 } | |
637 | |
638 | |
639 void MongooseServer::ClearHandlers() | |
640 { | |
641 Stop(); | |
642 | |
643 for (Handlers::iterator it = | |
644 handlers_.begin(); it != handlers_.end(); it++) | |
645 { | |
646 delete *it; | |
647 } | |
648 } | |
649 | |
23 | 650 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
651 void MongooseServer::ClearUsers() |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
652 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
653 Stop(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
654 registeredUsers_.clear(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
655 } |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
656 |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
657 |
23 | 658 void MongooseServer::RegisterUser(const char* username, |
659 const char* password) | |
660 { | |
661 Stop(); | |
24 | 662 |
663 std::string tag = std::string(username) + ":" + std::string(password); | |
664 registeredUsers_.insert(Toolbox::EncodeBase64(tag)); | |
23 | 665 } |
666 | |
667 void MongooseServer::SetSslEnabled(bool enabled) | |
668 { | |
669 Stop(); | |
670 | |
59 | 671 #if ORTHANC_SSL_ENABLED == 0 |
23 | 672 if (enabled) |
673 { | |
59 | 674 throw OrthancException("Orthanc has been built without SSL support"); |
23 | 675 } |
676 else | |
677 { | |
678 ssl_ = false; | |
679 } | |
680 #else | |
681 ssl_ = enabled; | |
682 #endif | |
683 } | |
684 | |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
685 void MongooseServer::SetAuthenticationEnabled(bool enabled) |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
686 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
687 Stop(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
688 authentication_ = enabled; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
689 } |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
690 |
23 | 691 void MongooseServer::SetSslCertificate(const char* path) |
692 { | |
693 Stop(); | |
694 certificate_ = path; | |
695 } | |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
696 |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
697 void MongooseServer::SetRemoteAccessAllowed(bool allowed) |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
698 { |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
699 Stop(); |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
700 remoteAllowed_ = allowed; |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
701 } |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
702 |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
703 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
704 bool MongooseServer::IsValidBasicHttpAuthentication(const std::string& basic) const |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
705 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
706 return registeredUsers_.find(basic) != registeredUsers_.end(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
707 } |
0 | 708 } |