Mercurial > hg > orthanc
comparison Core/HttpServer/MongooseServer.cpp @ 1112:a119f9ae3640
upgrade to Mongoose 3.8
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 01 Sep 2014 12:20:26 +0200 |
parents | becde5351e47 |
children | ba5c0908600c |
comparison
equal
deleted
inserted
replaced
1111:929bf8c2123d | 1112:a119f9ae3640 |
---|---|
545 | 545 |
546 return true; | 546 return true; |
547 } | 547 } |
548 | 548 |
549 | 549 |
550 | 550 static void InternalCallback(struct mg_connection *connection, |
551 const struct mg_request_info *request) | |
552 { | |
553 MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data); | |
554 MongooseOutputStream stream(connection); | |
555 HttpOutput output(stream); | |
556 | |
557 // Check remote calls | |
558 if (!that->IsRemoteAccessAllowed() && | |
559 request->remote_ip != LOCALHOST) | |
560 { | |
561 output.SendUnauthorized(ORTHANC_REALM); | |
562 return; | |
563 } | |
564 | |
565 | |
566 // Extract the HTTP headers | |
567 HttpHandler::Arguments headers; | |
568 for (int i = 0; i < request->num_headers; i++) | |
569 { | |
570 std::string name = request->http_headers[i].name; | |
571 std::transform(name.begin(), name.end(), name.begin(), ::tolower); | |
572 headers.insert(std::make_pair(name, request->http_headers[i].value)); | |
573 } | |
574 | |
575 | |
576 // Extract the GET arguments | |
577 HttpHandler::Arguments argumentsGET; | |
578 if (!strcmp(request->request_method, "GET")) | |
579 { | |
580 HttpHandler::ParseGetArguments(argumentsGET, request->query_string); | |
581 } | |
582 | |
583 | |
584 // Compute the HTTP method, taking method faking into consideration | |
585 HttpMethod method; | |
586 if (!ExtractMethod(method, request, headers, argumentsGET)) | |
587 { | |
588 output.SendHeader(HttpStatus_400_BadRequest); | |
589 return; | |
590 } | |
591 | |
592 | |
593 // Authenticate this connection | |
594 if (that->IsAuthenticationEnabled() && | |
595 !Authorize(*that, headers, output)) | |
596 { | |
597 return; | |
598 } | |
599 | |
600 | |
601 // Apply the filter, if it is installed | |
602 const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter(); | |
603 if (filter != NULL) | |
604 { | |
605 std::string username = GetAuthenticatedUsername(headers); | |
606 | |
607 char remoteIp[24]; | |
608 sprintf(remoteIp, "%d.%d.%d.%d", | |
609 reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], | |
610 reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], | |
611 reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], | |
612 reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]); | |
613 | |
614 if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str())) | |
615 { | |
616 output.SendUnauthorized(ORTHANC_REALM); | |
617 return; | |
618 } | |
619 } | |
620 | |
621 | |
622 // Extract the body of the request for PUT and POST | |
623 std::string body; | |
624 if (method == HttpMethod_Post || | |
625 method == HttpMethod_Put) | |
626 { | |
627 PostDataStatus status; | |
628 | |
629 HttpHandler::Arguments::const_iterator ct = headers.find("content-type"); | |
630 if (ct == headers.end()) | |
631 { | |
632 // No content-type specified. Assume no multi-part content occurs at this point. | |
633 status = ReadBody(body, connection, headers); | |
634 } | |
635 else | |
636 { | |
637 std::string contentType = ct->second; | |
638 if (contentType.size() >= multipartLength && | |
639 !memcmp(contentType.c_str(), multipart, multipartLength)) | |
640 { | |
641 status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore()); | |
642 } | |
643 else | |
644 { | |
645 status = ReadBody(body, connection, headers); | |
646 } | |
647 } | |
648 | |
649 switch (status) | |
650 { | |
651 case PostDataStatus_NoLength: | |
652 output.SendHeader(HttpStatus_411_LengthRequired); | |
653 return; | |
654 | |
655 case PostDataStatus_Failure: | |
656 output.SendHeader(HttpStatus_400_BadRequest); | |
657 return; | |
658 | |
659 case PostDataStatus_Pending: | |
660 output.AnswerBufferWithContentType(NULL, 0, ""); | |
661 return; | |
662 | |
663 default: | |
664 break; | |
665 } | |
666 } | |
667 | |
668 | |
669 // Decompose the URI into its components | |
670 UriComponents uri; | |
671 try | |
672 { | |
673 Toolbox::SplitUriComponents(uri, request->uri); | |
674 } | |
675 catch (OrthancException) | |
676 { | |
677 output.SendHeader(HttpStatus_400_BadRequest); | |
678 return; | |
679 } | |
680 | |
681 | |
682 // Loop over the candidate handlers for this URI | |
683 LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); | |
684 bool found = false; | |
685 | |
686 for (MongooseServer::Handlers::const_iterator it = | |
687 that->GetHandlers().begin(); it != that->GetHandlers().end() && !found; ++it) | |
688 { | |
689 try | |
690 { | |
691 found = (*it)->Handle(output, method, uri, headers, argumentsGET, body); | |
692 } | |
693 catch (OrthancException& e) | |
694 { | |
695 // Using this candidate handler results in an exception | |
696 LOG(ERROR) << "Exception in the HTTP handler: " << e.What(); | |
697 return; | |
698 } | |
699 catch (boost::bad_lexical_cast&) | |
700 { | |
701 LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast"; | |
702 return; | |
703 } | |
704 catch (std::runtime_error&) | |
705 { | |
706 LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request"; | |
707 return; | |
708 } | |
709 } | |
710 | |
711 if (!found) | |
712 { | |
713 try | |
714 { | |
715 output.SendHeader(HttpStatus_404_NotFound); | |
716 } | |
717 catch (OrthancException&) | |
718 { | |
719 } | |
720 } | |
721 } | |
722 | |
723 | |
724 #if MONGOOSE_USE_CALLBACKS == 0 | |
551 static void* Callback(enum mg_event event, | 725 static void* Callback(enum mg_event event, |
552 struct mg_connection *connection, | 726 struct mg_connection *connection, |
553 const struct mg_request_info *request) | 727 const struct mg_request_info *request) |
554 { | 728 { |
555 if (event == MG_NEW_REQUEST) | 729 if (event == MG_NEW_REQUEST) |
556 { | 730 { |
557 MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data); | 731 InternalCallback(connection, request); |
558 MongooseOutputStream stream(connection); | |
559 HttpOutput output(stream); | |
560 | |
561 // Check remote calls | |
562 if (!that->IsRemoteAccessAllowed() && | |
563 request->remote_ip != LOCALHOST) | |
564 { | |
565 output.SendUnauthorized(ORTHANC_REALM); | |
566 return (void*) ""; | |
567 } | |
568 | |
569 | |
570 // Extract the HTTP headers | |
571 HttpHandler::Arguments headers; | |
572 for (int i = 0; i < request->num_headers; i++) | |
573 { | |
574 std::string name = request->http_headers[i].name; | |
575 std::transform(name.begin(), name.end(), name.begin(), ::tolower); | |
576 headers.insert(std::make_pair(name, request->http_headers[i].value)); | |
577 } | |
578 | |
579 | |
580 // Extract the GET arguments | |
581 HttpHandler::Arguments argumentsGET; | |
582 if (!strcmp(request->request_method, "GET")) | |
583 { | |
584 HttpHandler::ParseGetArguments(argumentsGET, request->query_string); | |
585 } | |
586 | |
587 | |
588 // Compute the HTTP method, taking method faking into consideration | |
589 HttpMethod method; | |
590 if (!ExtractMethod(method, request, headers, argumentsGET)) | |
591 { | |
592 output.SendHeader(HttpStatus_400_BadRequest); | |
593 return (void*) ""; | |
594 } | |
595 | |
596 | |
597 // Authenticate this connection | |
598 if (that->IsAuthenticationEnabled() && | |
599 !Authorize(*that, headers, output)) | |
600 { | |
601 return (void*) ""; | |
602 } | |
603 | |
604 | |
605 // Apply the filter, if it is installed | |
606 const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter(); | |
607 if (filter != NULL) | |
608 { | |
609 std::string username = GetAuthenticatedUsername(headers); | |
610 | |
611 char remoteIp[24]; | |
612 sprintf(remoteIp, "%d.%d.%d.%d", | |
613 reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], | |
614 reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], | |
615 reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], | |
616 reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]); | |
617 | |
618 if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str())) | |
619 { | |
620 output.SendUnauthorized(ORTHANC_REALM); | |
621 return (void*) ""; | |
622 } | |
623 } | |
624 | |
625 | |
626 // Extract the body of the request for PUT and POST | |
627 std::string body; | |
628 if (method == HttpMethod_Post || | |
629 method == HttpMethod_Put) | |
630 { | |
631 PostDataStatus status; | |
632 | |
633 HttpHandler::Arguments::const_iterator ct = headers.find("content-type"); | |
634 if (ct == headers.end()) | |
635 { | |
636 // No content-type specified. Assume no multi-part content occurs at this point. | |
637 status = ReadBody(body, connection, headers); | |
638 } | |
639 else | |
640 { | |
641 std::string contentType = ct->second; | |
642 if (contentType.size() >= multipartLength && | |
643 !memcmp(contentType.c_str(), multipart, multipartLength)) | |
644 { | |
645 status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore()); | |
646 } | |
647 else | |
648 { | |
649 status = ReadBody(body, connection, headers); | |
650 } | |
651 } | |
652 | |
653 switch (status) | |
654 { | |
655 case PostDataStatus_NoLength: | |
656 output.SendHeader(HttpStatus_411_LengthRequired); | |
657 return (void*) ""; | |
658 | |
659 case PostDataStatus_Failure: | |
660 output.SendHeader(HttpStatus_400_BadRequest); | |
661 return (void*) ""; | |
662 | |
663 case PostDataStatus_Pending: | |
664 output.AnswerBufferWithContentType(NULL, 0, ""); | |
665 return (void*) ""; | |
666 | |
667 default: | |
668 break; | |
669 } | |
670 } | |
671 | |
672 | |
673 // Decompose the URI into its components | |
674 UriComponents uri; | |
675 try | |
676 { | |
677 Toolbox::SplitUriComponents(uri, request->uri); | |
678 } | |
679 catch (OrthancException) | |
680 { | |
681 output.SendHeader(HttpStatus_400_BadRequest); | |
682 return (void*) ""; | |
683 } | |
684 | |
685 | |
686 // Loop over the candidate handlers for this URI | |
687 LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); | |
688 bool found = false; | |
689 | |
690 for (MongooseServer::Handlers::const_iterator it = | |
691 that->GetHandlers().begin(); it != that->GetHandlers().end() && !found; ++it) | |
692 { | |
693 try | |
694 { | |
695 found = (*it)->Handle(output, method, uri, headers, argumentsGET, body); | |
696 } | |
697 catch (OrthancException& e) | |
698 { | |
699 // Using this candidate handler results in an exception | |
700 LOG(ERROR) << "Exception in the HTTP handler: " << e.What(); | |
701 return (void*) ""; | |
702 } | |
703 catch (boost::bad_lexical_cast&) | |
704 { | |
705 LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast"; | |
706 return (void*) ""; | |
707 } | |
708 catch (std::runtime_error&) | |
709 { | |
710 LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request"; | |
711 return (void*) ""; | |
712 } | |
713 } | |
714 | |
715 if (!found) | |
716 { | |
717 try | |
718 { | |
719 output.SendHeader(HttpStatus_404_NotFound); | |
720 } | |
721 catch (OrthancException&) | |
722 { | |
723 } | |
724 } | |
725 | 732 |
726 // Mark as processed | 733 // Mark as processed |
727 return (void*) ""; | 734 return (void*) ""; |
728 } | 735 } |
729 else | 736 else |
730 { | 737 { |
731 return NULL; | 738 return NULL; |
732 } | 739 } |
733 } | 740 } |
741 | |
742 #elif MONGOOSE_USE_CALLBACKS == 1 | |
743 static int Callback(struct mg_connection *connection) | |
744 { | |
745 struct mg_request_info *request = mg_get_request_info(connection); | |
746 | |
747 InternalCallback(connection, request); | |
748 | |
749 return 1; // Do not let Mongoose handle the request by itself | |
750 } | |
751 | |
752 #else | |
753 #error Please set MONGOOSE_USE_CALLBACKS | |
754 #endif | |
755 | |
756 | |
757 | |
734 | 758 |
735 | 759 |
736 bool MongooseServer::IsRunning() const | 760 bool MongooseServer::IsRunning() const |
737 { | 761 { |
738 return (pimpl_->context_ != NULL); | 762 return (pimpl_->context_ != NULL); |
796 ssl_ ? "ssl_certificate" : NULL, | 820 ssl_ ? "ssl_certificate" : NULL, |
797 certificate_.c_str(), | 821 certificate_.c_str(), |
798 NULL | 822 NULL |
799 }; | 823 }; |
800 | 824 |
825 #if MONGOOSE_USE_CALLBACKS == 0 | |
801 pimpl_->context_ = mg_start(&Callback, this, options); | 826 pimpl_->context_ = mg_start(&Callback, this, options); |
827 | |
828 #elif MONGOOSE_USE_CALLBACKS == 1 | |
829 struct mg_callbacks callbacks; | |
830 memset(&callbacks, 0, sizeof(callbacks)); | |
831 callbacks.begin_request = Callback; | |
832 pimpl_->context_ = mg_start(&callbacks, this, options); | |
833 | |
834 #else | |
835 #error Please set MONGOOSE_USE_CALLBACKS | |
836 #endif | |
837 | |
802 if (!pimpl_->context_) | 838 if (!pimpl_->context_) |
803 { | 839 { |
804 throw OrthancException("Unable to launch the Mongoose server"); | 840 throw OrthancException("Unable to launch the Mongoose server"); |
805 } | 841 } |
806 } | 842 } |