comparison Core/HttpServer/MongooseServer.cpp @ 2134:ddc75c6c712d

Avoid hard crash if not enough memory
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 Nov 2016 12:04:09 +0100
parents 15ae532af70e
children dd609a99d39a
comparison
equal deleted inserted replaced
2133:15ae532af70e 2134:ddc75c6c712d
573 } 573 }
574 } 574 }
575 } 575 }
576 576
577 577
578 static void InternalCallback(struct mg_connection *connection, 578 static void InternalCallback(HttpOutput& output /* out */,
579 HttpMethod& method /* out */,
580 MongooseServer& server,
581 struct mg_connection *connection,
579 const struct mg_request_info *request) 582 const struct mg_request_info *request)
580 { 583 {
581 MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
582
583 MongooseOutputStream stream(connection);
584 HttpOutput output(stream, that->IsKeepAliveEnabled());
585
586 // Check remote calls 584 // Check remote calls
587 if (!that->IsRemoteAccessAllowed() && 585 if (!server.IsRemoteAccessAllowed() &&
588 request->remote_ip != LOCALHOST) 586 request->remote_ip != LOCALHOST)
589 { 587 {
590 output.SendUnauthorized(ORTHANC_REALM); 588 output.SendUnauthorized(ORTHANC_REALM);
591 return; 589 return;
592 } 590 }
602 std::transform(name.begin(), name.end(), name.begin(), ::tolower); 600 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
603 headers.insert(std::make_pair(name, value)); 601 headers.insert(std::make_pair(name, value));
604 VLOG(1) << "HTTP header: [" << name << "]: [" << value << "]"; 602 VLOG(1) << "HTTP header: [" << name << "]: [" << value << "]";
605 } 603 }
606 604
607 if (that->IsHttpCompressionEnabled()) 605 if (server.IsHttpCompressionEnabled())
608 { 606 {
609 ConfigureHttpCompression(output, headers); 607 ConfigureHttpCompression(output, headers);
610 } 608 }
611 609
612 610
617 HttpToolbox::ParseGetArguments(argumentsGET, request->query_string); 615 HttpToolbox::ParseGetArguments(argumentsGET, request->query_string);
618 } 616 }
619 617
620 618
621 // Compute the HTTP method, taking method faking into consideration 619 // Compute the HTTP method, taking method faking into consideration
622 HttpMethod method = HttpMethod_Get; 620 method = HttpMethod_Get;
623 if (!ExtractMethod(method, request, headers, argumentsGET)) 621 if (!ExtractMethod(method, request, headers, argumentsGET))
624 { 622 {
625 output.SendStatus(HttpStatus_400_BadRequest); 623 output.SendStatus(HttpStatus_400_BadRequest);
626 return; 624 return;
627 } 625 }
628 626
629 627
630 // Authenticate this connection 628 // Authenticate this connection
631 if (that->IsAuthenticationEnabled() && !IsAccessGranted(*that, headers)) 629 if (server.IsAuthenticationEnabled() &&
630 !IsAccessGranted(server, headers))
632 { 631 {
633 output.SendUnauthorized(ORTHANC_REALM); 632 output.SendUnauthorized(ORTHANC_REALM);
634 return; 633 return;
635 } 634 }
636 635
643 reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], 642 reinterpret_cast<const uint8_t*>(&request->remote_ip) [1],
644 reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]); 643 reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]);
645 644
646 std::string username = GetAuthenticatedUsername(headers); 645 std::string username = GetAuthenticatedUsername(headers);
647 646
648 const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter(); 647 const IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter();
649 if (filter != NULL) 648 if (filter != NULL)
650 { 649 {
651 if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str(), headers)) 650 if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str(), headers))
652 { 651 {
653 //output.SendUnauthorized(ORTHANC_REALM); 652 //output.SendUnauthorized(ORTHANC_REALM);
677 { 676 {
678 std::string contentType = ct->second; 677 std::string contentType = ct->second;
679 if (contentType.size() >= multipartLength && 678 if (contentType.size() >= multipartLength &&
680 !memcmp(contentType.c_str(), multipart, multipartLength)) 679 !memcmp(contentType.c_str(), multipart, multipartLength))
681 { 680 {
682 status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore()); 681 status = ParseMultipartPost(body, connection, headers, contentType, server.GetChunkStore());
683 } 682 }
684 else 683 else
685 { 684 {
686 status = ReadBody(body, connection, headers); 685 status = ReadBody(body, connection, headers);
687 } 686 }
711 UriComponents uri; 710 UriComponents uri;
712 try 711 try
713 { 712 {
714 Toolbox::SplitUriComponents(uri, request->uri); 713 Toolbox::SplitUriComponents(uri, request->uri);
715 } 714 }
716 catch (OrthancException) 715 catch (OrthancException&)
717 { 716 {
718 output.SendStatus(HttpStatus_400_BadRequest); 717 output.SendStatus(HttpStatus_400_BadRequest);
719 return; 718 return;
720 } 719 }
721 720
722 721
723 LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); 722 LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
724 723
725 724 bool found = false;
725
726 if (server.HasHandler())
727 {
728 found = server.GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(),
729 method, uri, headers, argumentsGET, body.c_str(), body.size());
730 }
731
732 if (!found)
733 {
734 throw OrthancException(ErrorCode_UnknownResource);
735 }
736 }
737
738
739 static void ProtectedCallback(struct mg_connection *connection,
740 const struct mg_request_info *request)
741 {
726 try 742 try
727 { 743 {
728 bool found = false; 744 MongooseServer* server = reinterpret_cast<MongooseServer*>(request->user_data);
745
746 if (server == NULL)
747 {
748 MongooseOutputStream stream(connection);
749 HttpOutput output(stream, false /* assume no keep-alive */);
750 output.SendStatus(HttpStatus_500_InternalServerError);
751 return;
752 }
753
754 MongooseOutputStream stream(connection);
755 HttpOutput output(stream, server->IsKeepAliveEnabled());
756 HttpMethod method = HttpMethod_Get;
729 757
730 try 758 try
731 { 759 {
732 if (that->HasHandler()) 760 try
733 { 761 {
734 found = that->GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(), 762 InternalCallback(output, method, *server, connection, request);
735 method, uri, headers, argumentsGET, body.c_str(), body.size()); 763 }
736 } 764 catch (OrthancException&)
737 } 765 {
738 catch (boost::bad_lexical_cast&) 766 throw; // Pass the exception to the main handler below
739 { 767 }
740 throw OrthancException(ErrorCode_BadParameterType); 768 // Now convert native exceptions as OrthancException
741 } 769 catch (boost::bad_lexical_cast&)
742 catch (std::runtime_error&) 770 {
743 { 771 LOG(ERROR) << "Syntax error in some user-supplied data";
744 // Presumably an error while parsing the JSON body 772 throw OrthancException(ErrorCode_BadParameterType);
745 throw OrthancException(ErrorCode_BadRequest); 773 }
746 } 774 catch (std::runtime_error&)
747 /*catch (std::bad_alloc&) 775 {
748 { 776 // Presumably an error while parsing the JSON body
749 throw OrthancException(ErrorCode_NotEnoughMemory); 777 throw OrthancException(ErrorCode_BadRequest);
750 }*/ 778 }
751 779 catch (std::bad_alloc&)
752 if (!found) 780 {
753 { 781 LOG(ERROR) << "The server hosting Orthanc is running out of memory";
754 throw OrthancException(ErrorCode_UnknownResource); 782 throw OrthancException(ErrorCode_NotEnoughMemory);
755 } 783 }
756 } 784 catch (...)
757 catch (OrthancException& e) 785 {
758 { 786 LOG(ERROR) << "An unhandled exception was generated inside the HTTP server";
759 // Using this candidate handler results in an exception 787 throw OrthancException(ErrorCode_InternalError);
760 try 788 }
761 { 789 }
762 if (that->GetExceptionFormatter() == NULL) 790 catch (OrthancException& e)
763 { 791 {
764 LOG(ERROR) << "Exception in the HTTP handler: " << e.What(); 792 assert(server != NULL);
765 output.SendStatus(e.GetHttpStatus()); 793
766 } 794 // Using this candidate handler results in an exception
767 else 795 try
768 { 796 {
769 that->GetExceptionFormatter()->Format(output, e, method, request->uri); 797 if (server->GetExceptionFormatter() == NULL)
770 } 798 {
771 } 799 LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
772 catch (OrthancException&) 800 output.SendStatus(e.GetHttpStatus());
773 { 801 }
774 // An exception here reflects the fact that the status code 802 else
775 // was already set by the HTTP handler. 803 {
776 } 804 server->GetExceptionFormatter()->Format(output, e, method, request->uri);
777 805 }
778 return; 806 }
807 catch (OrthancException&)
808 {
809 // An exception here reflects the fact that the status code
810 // was already set by the HTTP handler.
811 }
812 }
813 }
814 catch (...)
815 {
816 // We should never arrive at this point, where it is even impossible to send an answer
817 LOG(ERROR) << "Catastrophic error inside the HTTP server, giving up";
779 } 818 }
780 } 819 }
781 820
782 821
783 #if MONGOOSE_USE_CALLBACKS == 0 822 #if MONGOOSE_USE_CALLBACKS == 0
785 struct mg_connection *connection, 824 struct mg_connection *connection,
786 const struct mg_request_info *request) 825 const struct mg_request_info *request)
787 { 826 {
788 if (event == MG_NEW_REQUEST) 827 if (event == MG_NEW_REQUEST)
789 { 828 {
790 InternalCallback(connection, request); 829 ProtectedCallback(connection, request);
791 830
792 // Mark as processed 831 // Mark as processed
793 return (void*) ""; 832 return (void*) "";
794 } 833 }
795 else 834 else
801 #elif MONGOOSE_USE_CALLBACKS == 1 840 #elif MONGOOSE_USE_CALLBACKS == 1
802 static int Callback(struct mg_connection *connection) 841 static int Callback(struct mg_connection *connection)
803 { 842 {
804 struct mg_request_info *request = mg_get_request_info(connection); 843 struct mg_request_info *request = mg_get_request_info(connection);
805 844
806 InternalCallback(connection, request); 845 ProtectedCallback(connection, request);
807 846
808 return 1; // Do not let Mongoose handle the request by itself 847 return 1; // Do not let Mongoose handle the request by itself
809 } 848 }
810 849
811 #else 850 #else