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