comparison Plugins/Samples/Common/OrthancPluginCppWrapper.h @ 3415:2a821deece64

refactoring to handle "not allowed" HTTP status 405
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 11 Jun 2019 21:06:57 +0200
parents b9cba6a91780
children 541c787e2230
comparison
equal deleted inserted replaced
3414:b9cba6a91780 3415:2a821deece64
552 552
553 553
554 namespace Internals 554 namespace Internals
555 { 555 {
556 template <RestCallback Callback> 556 template <RestCallback Callback>
557 OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output, 557 static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output,
558 const char* url, 558 const char* url,
559 const OrthancPluginHttpRequest* request) 559 const OrthancPluginHttpRequest* request)
560 { 560 {
561 try 561 try
562 { 562 {
563 Callback(output, url, request); 563 Callback(output, url, request);
564 return OrthancPluginErrorCode_Success; 564 return OrthancPluginErrorCode_Success;
932 932
933 virtual void Execute(OrthancPluginRestOutput* output) = 0; 933 virtual void Execute(OrthancPluginRestOutput* output) = 0;
934 }; 934 };
935 935
936 936
937 typedef IChunkedRequestReader* (*ChunkedRestCallback) (OrthancPluginRestOutput* output, 937 typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url,
938 const char* url,
939 const OrthancPluginHttpRequest* request); 938 const OrthancPluginHttpRequest* request);
940 939
941 940
942 namespace Internals 941 namespace Internals
943 { 942 {
943 inline void NullRestCallback(OrthancPluginRestOutput* output,
944 const char* url,
945 const OrthancPluginHttpRequest* request)
946 {
947 }
948
949 inline IChunkedRequestReader *NullChunkedRestCallback(const char* url,
950 const OrthancPluginHttpRequest* request)
951 {
952 return NULL;
953 }
954
955
944 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 956 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
945 template <ChunkedRestCallback Callback> 957 template <ChunkedRestCallback Callback>
946 OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output, 958 static OrthancPluginErrorCode Protect(OrthancPluginServerChunkedRequestReader** reader,
947 OrthancPluginServerChunkedRequestReader** reader, 959 const char* url,
948 const char* url, 960 const OrthancPluginHttpRequest* request)
949 const OrthancPluginHttpRequest* request)
950 {
951 try
952 {
953 switch (request->method)
954 {
955 case OrthancPluginHttpMethod_Get:
956 case OrthancPluginHttpMethod_Delete:
957 if (output == NULL ||
958 reader != NULL ||
959 Callback(output, url, request) != NULL)
960 {
961 return OrthancPluginErrorCode_InternalError;
962 }
963
964 return OrthancPluginErrorCode_Success;
965
966 case OrthancPluginHttpMethod_Post:
967 case OrthancPluginHttpMethod_Put:
968 if (output != NULL ||
969 reader == NULL)
970 {
971 return OrthancPluginErrorCode_InternalError;
972 }
973 else
974 {
975 *reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(NULL, url, request));
976 if (*reader == NULL)
977 {
978 return OrthancPluginErrorCode_Plugin;
979 }
980 }
981
982 return OrthancPluginErrorCode_Success;
983
984 default:
985 return OrthancPluginErrorCode_InternalError;
986 }
987 }
988 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
989 {
990 #if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1
991 if (HasGlobalContext() &&
992 e.HasDetails())
993 {
994 // The "false" instructs Orthanc not to log the detailed
995 // error message. This is to avoid duplicating the details,
996 // because "OrthancException" already does it on construction.
997 OrthancPluginSetHttpErrorDetails
998 (GetGlobalContext(), output, e.GetDetails(), false);
999 }
1000 #endif
1001
1002 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
1003 }
1004 catch (boost::bad_lexical_cast&)
1005 {
1006 return OrthancPluginErrorCode_BadFileFormat;
1007 }
1008 catch (...)
1009 {
1010 return OrthancPluginErrorCode_Plugin;
1011 }
1012 }
1013
1014 static OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
1015 OrthancPluginServerChunkedRequestReader* reader,
1016 const void* data,
1017 uint32_t size)
1018 { 961 {
1019 try 962 try
1020 { 963 {
1021 if (reader == NULL) 964 if (reader == NULL)
1022 { 965 {
1023 return OrthancPluginErrorCode_InternalError; 966 return OrthancPluginErrorCode_InternalError;
1024 } 967 }
1025 968 else
1026 reinterpret_cast<IChunkedRequestReader*>(reader)->AddChunk(data, size); 969 {
1027 return OrthancPluginErrorCode_Success; 970 *reader = reinterpret_cast<OrthancPluginServerChunkedRequestReader*>(Callback(url, request));
971 if (*reader == NULL)
972 {
973 return OrthancPluginErrorCode_Plugin;
974 }
975 else
976 {
977 return OrthancPluginErrorCode_Success;
978 }
979 }
1028 } 980 }
1029 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) 981 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
1030 { 982 {
1031 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); 983 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
1032 } 984 }
1038 { 990 {
1039 return OrthancPluginErrorCode_Plugin; 991 return OrthancPluginErrorCode_Plugin;
1040 } 992 }
1041 } 993 }
1042 994
1043 static OrthancPluginErrorCode ChunkedRequestReaderExecute( 995 static inline OrthancPluginErrorCode ChunkedRequestReaderAddChunk(
1044 OrthancPluginServerChunkedRequestReader* reader, 996 OrthancPluginServerChunkedRequestReader* reader,
1045 OrthancPluginRestOutput* output) 997 const void* data,
998 uint32_t size)
1046 { 999 {
1047 try 1000 try
1048 { 1001 {
1049 if (reader == NULL) 1002 if (reader == NULL)
1050 { 1003 {
1051 return OrthancPluginErrorCode_InternalError; 1004 return OrthancPluginErrorCode_InternalError;
1052 } 1005 }
1053 1006
1007 reinterpret_cast<IChunkedRequestReader*>(reader)->AddChunk(data, size);
1008 return OrthancPluginErrorCode_Success;
1009 }
1010 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
1011 {
1012 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
1013 }
1014 catch (boost::bad_lexical_cast&)
1015 {
1016 return OrthancPluginErrorCode_BadFileFormat;
1017 }
1018 catch (...)
1019 {
1020 return OrthancPluginErrorCode_Plugin;
1021 }
1022 }
1023
1024 static inline OrthancPluginErrorCode ChunkedRequestReaderExecute(
1025 OrthancPluginServerChunkedRequestReader* reader,
1026 OrthancPluginRestOutput* output)
1027 {
1028 try
1029 {
1030 if (reader == NULL)
1031 {
1032 return OrthancPluginErrorCode_InternalError;
1033 }
1034
1054 reinterpret_cast<IChunkedRequestReader*>(reader)->Execute(output); 1035 reinterpret_cast<IChunkedRequestReader*>(reader)->Execute(output);
1055 return OrthancPluginErrorCode_Success; 1036 return OrthancPluginErrorCode_Success;
1056 } 1037 }
1057 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) 1038 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
1058 { 1039 {
1066 { 1047 {
1067 return OrthancPluginErrorCode_Plugin; 1048 return OrthancPluginErrorCode_Plugin;
1068 } 1049 }
1069 } 1050 }
1070 1051
1071 static void ChunkedRequestReaderFinalize( 1052 static inline void ChunkedRequestReaderFinalize(
1072 OrthancPluginServerChunkedRequestReader* reader) 1053 OrthancPluginServerChunkedRequestReader* reader)
1073 { 1054 {
1074 if (reader != NULL) 1055 if (reader != NULL)
1075 { 1056 {
1076 delete reinterpret_cast<IChunkedRequestReader*>(reader); 1057 delete reinterpret_cast<IChunkedRequestReader*>(reader);
1077 } 1058 }
1078 } 1059 }
1079 1060
1080 #else 1061 #else
1081 1062
1082 template <ChunkedRestCallback Callback> 1063 template<
1083 void ChunkedRestCompatibility(OrthancPluginRestOutput* output, 1064 RestCallback GetHandler,
1084 const char* url, 1065 ChunkedRestCallback PostHandler,
1085 const OrthancPluginHttpRequest* request) 1066 RestCallback DeleteHandler,
1086 { 1067 ChunkedRestCallback PutHandler
1068 >
1069 static void ChunkedRestCompatibility(OrthancPluginRestOutput* output,
1070 const char* url,
1071 const OrthancPluginHttpRequest* request)
1072 {
1073 std::string allowed;
1074
1075 if (GetHandler != Internals::NullRestCallback)
1076 {
1077 allowed += "GET";
1078 }
1079
1080 if (PostHandler != Internals::NullChunkedRestCallback)
1081 {
1082 if (!allowed.empty())
1083 {
1084 allowed += ",";
1085 }
1086
1087 allowed += "POST";
1088 }
1089
1090 if (DeleteHandler != Internals::NullRestCallback)
1091 {
1092 if (!allowed.empty())
1093 {
1094 allowed += ",";
1095 }
1096
1097 allowed += "DELETE";
1098 }
1099
1100 if (PutHandler != Internals::NullChunkedRestCallback)
1101 {
1102 if (!allowed.empty())
1103 {
1104 allowed += ",";
1105 }
1106
1107 allowed += "PUT";
1108 }
1109
1087 switch (request->method) 1110 switch (request->method)
1088 { 1111 {
1089 case OrthancPluginHttpMethod_Get: 1112 case OrthancPluginHttpMethod_Get:
1090 case OrthancPluginHttpMethod_Delete: 1113 {
1091 if (Callback(output, url, request) != NULL) 1114 if (GetHandler == Internals::NullRestCallback)
1092 { 1115 {
1093 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 1116 OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str());
1094 } 1117 }
1095 else 1118 else
1096 { 1119 {
1097 return; 1120 GetHandler(output, url, request);
1098 } 1121 }
1122 return;
1123 }
1099 1124
1100 case OrthancPluginHttpMethod_Post: 1125 case OrthancPluginHttpMethod_Post:
1101 case OrthancPluginHttpMethod_Put:
1102 { 1126 {
1103 std::auto_ptr<IChunkedRequestReader> reader(Callback(NULL, url, request)); 1127 if (PostHandler == Internals::NullChunkedRestCallback)
1104 if (reader.get() == NULL)
1105 { 1128 {
1106 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 1129 OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str());
1107 } 1130 }
1108 else 1131 else
1109 { 1132 {
1110 if (request->bodySize != 0) 1133 std::auto_ptr<IChunkedRequestReader> reader(PostHandler(url, request));
1134 if (reader.get() == NULL)
1135 {
1136 ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin);
1137 }
1138 else
1111 { 1139 {
1112 reader->AddChunk(request->body, request->bodySize); 1140 reader->AddChunk(request->body, request->bodySize);
1141 reader->Execute(output);
1113 } 1142 }
1114 reader->Execute(output);
1115 } 1143 }
1116 return; 1144 return;
1117 } 1145 }
1118 1146
1147 case OrthancPluginHttpMethod_Delete:
1148 {
1149 if (DeleteHandler == Internals::NullRestCallback)
1150 {
1151 OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str());
1152 }
1153 else
1154 {
1155 DeleteHandler(output, url, request);
1156 }
1157 return;
1158 }
1159
1160 case OrthancPluginHttpMethod_Put:
1161 {
1162 if (PutHandler == Internals::NullChunkedRestCallback)
1163 {
1164 OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str());
1165 }
1166 else
1167 {
1168 std::auto_ptr<IChunkedRequestReader> reader(PutHandler(url, request));
1169 if (reader.get() == NULL)
1170 {
1171 ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin);
1172 }
1173 else
1174 {
1175 reader->AddChunk(request->body, request->bodySize);
1176 reader->Execute(output);
1177 }
1178 }
1179 return;
1180 }
1181
1119 default: 1182 default:
1120 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 1183 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
1121 } 1184 }
1122 } 1185 }
1123 #endif 1186 #endif
1124 } 1187 }
1125 1188
1126 1189
1127 template <ChunkedRestCallback Callback> 1190
1191 template<
1192 RestCallback GetHandler = Internals::NullRestCallback,
1193 ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback,
1194 RestCallback DeleteHandler = Internals::NullRestCallback,
1195 ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback
1196 >
1128 void RegisterChunkedRestCallback(const std::string& uri) 1197 void RegisterChunkedRestCallback(const std::string& uri)
1129 { 1198 {
1130 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 1199 #if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1
1131 OrthancPluginRegisterChunkedRestCallback( 1200 OrthancPluginRegisterChunkedRestCallback(
1132 GetGlobalContext(), uri.c_str(), Internals::Protect<Callback>, 1201 GetGlobalContext(), uri.c_str(),
1202 GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect<GetHandler>,
1203 PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::Protect<PostHandler>,
1204 DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect<DeleteHandler>,
1205 PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::Protect<PutHandler>,
1133 Internals::ChunkedRequestReaderAddChunk, 1206 Internals::ChunkedRequestReaderAddChunk,
1134 Internals::ChunkedRequestReaderExecute, 1207 Internals::ChunkedRequestReaderExecute,
1135 Internals::ChunkedRequestReaderFinalize); 1208 Internals::ChunkedRequestReaderFinalize);
1136 #else 1209 #else
1137 LogWarning("Performance warning: The plugin was compiled against a pre-1.5.7 version " 1210 LogWarning("Performance warning: The plugin was compiled against a pre-1.5.7 version "
1138 "of the Orthanc SDK. Multipart transfers will be entirely stored in RAM."); 1211 "of the Orthanc SDK. Multipart transfers will be entirely stored in RAM.");
1139 OrthancPluginRegisterRestCallback( 1212 OrthancPluginRegisterRestCallback(
1140 GetGlobalContext(), uri.c_str(), 1213 GetGlobalContext(), uri.c_str(),
1141 Internals::Protect< Internals::ChunkedRestCompatibility<Callback> >); 1214 Internals::Protect< Internals::ChunkedRestCompatibility<
1215 GetHandler, PostHandler, DeleteHandler, PutHandler> >);
1142 #endif 1216 #endif
1143 } 1217 }
1144 } 1218 }