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 }