Mercurial > hg > orthanc
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 |