Mercurial > hg > orthanc
annotate Core/HttpServer/MongooseServer.cpp @ 142:e7e19f042eb5
fix
author | jodogne |
---|---|
date | Thu, 11 Oct 2012 13:57:56 +0200 |
parents | fe180eae201d |
children | 93e1b0e3b83a |
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 } | |
492 else if (!strcmp(request->request_method, "POST")) | |
493 { | |
494 HttpHandler::Arguments::const_iterator ct = headers.find("content-type"); | |
495 if (ct == headers.end()) | |
496 { | |
59 | 497 output.SendHeader(Orthanc_HttpStatus_400_BadRequest); |
0 | 498 return (void*) ""; |
499 } | |
500 | |
501 PostDataStatus status; | |
502 | |
503 std::string contentType = ct->second; | |
504 if (contentType.size() >= multipartLength && | |
505 !memcmp(contentType.c_str(), multipart, multipartLength)) | |
506 { | |
507 status = ParseMultipartPost(postData, connection, headers, contentType, that->GetChunkStore()); | |
508 } | |
509 else | |
510 { | |
511 status = ReadPostData(postData, connection, headers); | |
512 } | |
513 | |
514 switch (status) | |
515 { | |
516 case PostDataStatus_NoLength: | |
59 | 517 output.SendHeader(Orthanc_HttpStatus_411_LengthRequired); |
0 | 518 return (void*) ""; |
519 | |
520 case PostDataStatus_Failure: | |
59 | 521 output.SendHeader(Orthanc_HttpStatus_400_BadRequest); |
0 | 522 return (void*) ""; |
523 | |
524 case PostDataStatus_Pending: | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
525 output.AnswerBuffer(""); |
0 | 526 return (void*) ""; |
527 | |
528 default: | |
529 break; | |
530 } | |
531 } | |
532 | |
533 UriComponents uri; | |
534 Toolbox::SplitUriComponents(uri, request->uri); | |
535 | |
536 HttpHandler* handler = that->FindHandler(uri); | |
537 if (handler) | |
538 { | |
539 try | |
540 { | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
541 handler->Handle(output, std::string(request->request_method), |
0 | 542 uri, headers, arguments, postData); |
543 } | |
59 | 544 catch (OrthancException& e) |
0 | 545 { |
108 | 546 LOG(ERROR) << "MongooseServer Exception [" << e.What() << "]"; |
59 | 547 output.SendHeader(Orthanc_HttpStatus_500_InternalServerError); |
0 | 548 } |
549 } | |
550 else | |
551 { | |
59 | 552 output.SendHeader(Orthanc_HttpStatus_404_NotFound); |
0 | 553 } |
554 | |
555 // Mark as processed | |
556 return (void*) ""; | |
557 } | |
558 else | |
559 { | |
560 return NULL; | |
561 } | |
562 } | |
563 | |
564 | |
565 bool MongooseServer::IsRunning() const | |
566 { | |
567 return (pimpl_->context_ != NULL); | |
568 } | |
569 | |
570 | |
571 MongooseServer::MongooseServer() : pimpl_(new PImpl) | |
572 { | |
573 pimpl_->context_ = NULL; | |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
574 remoteAllowed_ = false; |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
575 authentication_ = false; |
23 | 576 ssl_ = false; |
0 | 577 port_ = 8000; |
578 } | |
579 | |
580 | |
581 MongooseServer::~MongooseServer() | |
582 { | |
583 Stop(); | |
584 ClearHandlers(); | |
585 } | |
586 | |
587 | |
128 | 588 void MongooseServer::SetPortNumber(uint16_t port) |
0 | 589 { |
590 Stop(); | |
591 port_ = port; | |
592 } | |
593 | |
594 void MongooseServer::Start() | |
595 { | |
596 if (!IsRunning()) | |
597 { | |
598 std::string port = boost::lexical_cast<std::string>(port_); | |
599 | |
23 | 600 if (ssl_) |
601 { | |
602 port += "s"; | |
603 } | |
604 | |
0 | 605 const char *options[] = { |
606 "listening_ports", port.c_str(), | |
23 | 607 ssl_ ? "ssl_certificate" : NULL, |
608 certificate_.c_str(), | |
0 | 609 NULL |
610 }; | |
611 | |
612 pimpl_->context_ = mg_start(&Callback, this, options); | |
613 if (!pimpl_->context_) | |
614 { | |
59 | 615 throw OrthancException("Unable to launch the Mongoose server"); |
0 | 616 } |
617 } | |
618 } | |
619 | |
620 void MongooseServer::Stop() | |
621 { | |
622 if (IsRunning()) | |
623 { | |
624 mg_stop(pimpl_->context_); | |
625 pimpl_->context_ = NULL; | |
626 } | |
627 } | |
628 | |
629 | |
630 void MongooseServer::RegisterHandler(HttpHandler* handler) | |
631 { | |
632 Stop(); | |
633 | |
634 handlers_.push_back(handler); | |
635 } | |
636 | |
637 | |
638 void MongooseServer::ClearHandlers() | |
639 { | |
640 Stop(); | |
641 | |
642 for (Handlers::iterator it = | |
643 handlers_.begin(); it != handlers_.end(); it++) | |
644 { | |
645 delete *it; | |
646 } | |
647 } | |
648 | |
23 | 649 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
650 void MongooseServer::ClearUsers() |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
651 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
652 Stop(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
653 registeredUsers_.clear(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
654 } |
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 |
23 | 657 void MongooseServer::RegisterUser(const char* username, |
658 const char* password) | |
659 { | |
660 Stop(); | |
24 | 661 |
662 std::string tag = std::string(username) + ":" + std::string(password); | |
663 registeredUsers_.insert(Toolbox::EncodeBase64(tag)); | |
23 | 664 } |
665 | |
666 void MongooseServer::SetSslEnabled(bool enabled) | |
667 { | |
668 Stop(); | |
669 | |
59 | 670 #if ORTHANC_SSL_ENABLED == 0 |
23 | 671 if (enabled) |
672 { | |
59 | 673 throw OrthancException("Orthanc has been built without SSL support"); |
23 | 674 } |
675 else | |
676 { | |
677 ssl_ = false; | |
678 } | |
679 #else | |
680 ssl_ = enabled; | |
681 #endif | |
682 } | |
683 | |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
684 void MongooseServer::SetAuthenticationEnabled(bool enabled) |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
685 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
686 Stop(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
687 authentication_ = enabled; |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
688 } |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
689 |
23 | 690 void MongooseServer::SetSslCertificate(const char* path) |
691 { | |
692 Stop(); | |
693 certificate_ = path; | |
694 } | |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
695 |
34
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
696 void MongooseServer::SetRemoteAccessAllowed(bool allowed) |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
697 { |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
698 Stop(); |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
699 remoteAllowed_ = allowed; |
96e57b863dd9
option to disallow remote access
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
700 } |
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 |
25
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
703 bool MongooseServer::IsValidBasicHttpAuthentication(const std::string& basic) const |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
704 { |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
705 return registeredUsers_.find(basic) != registeredUsers_.end(); |
dd1489098265
basic http authentication
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
24
diff
changeset
|
706 } |
0 | 707 } |