changeset 2905:ae20fccdd867

refactoring mime types
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 30 Oct 2018 11:55:23 +0100
parents 0dd54ee073db
children 2a504fef4ed7
files Core/DicomFormat/DicomValue.h Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/ParsedDicomFile.cpp Core/DicomParsing/ParsedDicomFile.h Core/Enumerations.h Core/HttpServer/HttpFileSender.cpp Core/HttpServer/HttpOutput.cpp Core/RestApi/RestApi.cpp Core/RestApi/RestApiOutput.cpp Core/Toolbox.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancRestApi/OrthancRestApi.cpp OrthancServer/OrthancRestApi/OrthancRestChanges.cpp OrthancServer/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/OrthancRestApi/OrthancRestSystem.cpp OrthancServer/ServerEnumerations.cpp UnitTestsSources/UnitTestsMain.cpp
diffstat 18 files changed, 139 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomValue.h	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/DicomFormat/DicomValue.h	Tue Oct 30 11:55:23 2018 +0100
@@ -33,8 +33,9 @@
 
 #pragma once
 
+#include "../Enumerations.h"
+
 #include <stdint.h>
-#include <string>
 #include <boost/noncopyable.hpp>
 #include <json/value.h>
 
@@ -92,7 +93,7 @@
 
     void FormatDataUriScheme(std::string& target) const
     {
-      FormatDataUriScheme(target, "application/octet-stream");
+      FormatDataUriScheme(target, MIME_BINARY);
     }
 #endif
 
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -1511,7 +1511,7 @@
     const std::string* decoded = &utf8Value;
 
     if (decodeDataUriScheme &&
-        boost::starts_with(utf8Value, "data:application/octet-stream;base64,"))
+        boost::starts_with(utf8Value, URI_SCHEME_PREFIX_BINARY))
     {
       std::string mime;
       if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value))
--- a/Core/DicomParsing/ParsedDicomFile.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/DicomParsing/ParsedDicomFile.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -82,8 +82,10 @@
 #include "ParsedDicomFile.h"
 
 #include "FromDcmtkBridge.h"
+#include "Internals/DicomFrameIndex.h"
 #include "ToDcmtkBridge.h"
-#include "Internals/DicomFrameIndex.h"
+
+#include "../Images/PamReader.h"
 #include "../Logging.h"
 #include "../OrthancException.h"
 #include "../Toolbox.h"
@@ -160,8 +162,6 @@
 
 
 #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1
-  static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream";
-
   static void ParseTagAndGroup(DcmTagKey& key,
                                const std::string& tag)
   {
@@ -362,14 +362,14 @@
             {
               if (pixelItem->getLength() == 0)
               {
-                output.AnswerBuffer(NULL, 0, CONTENT_TYPE_OCTET_STREAM);
+                output.AnswerBuffer(NULL, 0, MIME_BINARY);
                 return true;
               }
 
               Uint8* buffer = NULL;
               if (pixelItem->getUint8Array(buffer).good() && buffer)
               {
-                output.AnswerBuffer(buffer, pixelItem->getLength(), CONTENT_TYPE_OCTET_STREAM);
+                output.AnswerBuffer(buffer, pixelItem->getLength(), MIME_BINARY);
                 return true;
               }
             }
@@ -692,7 +692,7 @@
     const std::string* decoded = &utf8Value;
 
     if (decodeDataUriScheme &&
-        boost::starts_with(utf8Value, "data:application/octet-stream;base64,"))
+        boost::starts_with(utf8Value, URI_SCHEME_PREFIX_BINARY))
     {
       std::string mime;
       if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value))
@@ -825,7 +825,7 @@
     std::string serialized;
     if (FromDcmtkBridge::SaveToMemoryBuffer(serialized, *pimpl_->file_->getDataset()))
     {
-      output.AnswerBuffer(serialized, CONTENT_TYPE_OCTET_STREAM);
+      output.AnswerBuffer(serialized, MIME_BINARY);
     }
   }
 #endif
@@ -1072,7 +1072,7 @@
 
     Toolbox::ToLowerCase(mime);
 
-    if (mime == "image/png")
+    if (mime == MIME_PNG)
     {
 #if ORTHANC_ENABLE_PNG == 1
       EmbedImage(mime, content);
@@ -1081,7 +1081,7 @@
       throw OrthancException(ErrorCode_NotImplemented);
 #endif
     }
-    else if (mime == "image/jpeg")
+    else if (mime == MIME_JPEG)
     {
 #if ORTHANC_ENABLE_JPEG == 1
       EmbedImage(mime, content);
@@ -1090,7 +1090,11 @@
       throw OrthancException(ErrorCode_NotImplemented);
 #endif
     }
-    else if (mime == "application/pdf")
+    else if (mime == MIME_PAM)
+    {
+      EmbedImage(mime, content);
+    }
+    else if (mime == MIME_PDF)
     {
       EmbedPdf(content);
     }
@@ -1113,20 +1117,32 @@
   }
 
 
-#if (ORTHANC_ENABLE_JPEG == 1 &&                \
-     ORTHANC_ENABLE_PNG == 1)
   void ParsedDicomFile::EmbedImage(const std::string& mime,
                                    const std::string& content)
   {
-    if (mime == "image/png")
+#if ORTHANC_ENABLE_JPEG == 1
+    if (mime == MIME_JPEG)
+    {
+      JpegReader reader;
+      reader.ReadFromMemory(content);
+      EmbedImage(reader);
+      return;
+    }
+#endif
+    
+#if ORTHANC_ENABLE_PNG == 1
+    if (mime == MIME_PNG)
     {
       PngReader reader;
       reader.ReadFromMemory(content);
       EmbedImage(reader);
+      return;
     }
-    else if (mime == "image/jpeg")
+#endif
+
+    if (mime == MIME_PAM)
     {
-      JpegReader reader;
+      PamReader reader;
       reader.ReadFromMemory(content);
       EmbedImage(reader);
     }
@@ -1135,7 +1151,6 @@
       throw OrthancException(ErrorCode_NotImplemented);
     }
   }
-#endif
 
 
   void ParsedDicomFile::EmbedImage(const ImageAccessor& accessor)
@@ -1346,7 +1361,7 @@
     ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage);
     ReplacePlainString(FromDcmtkBridge::Convert(DCM_Modality), "OT");
     ReplacePlainString(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD");
-    ReplacePlainString(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), "application/pdf");
+    ReplacePlainString(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), MIME_PDF);
     //ReplacePlainString(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1");
 
     std::auto_ptr<DcmPolymorphOBOW> element(new DcmPolymorphOBOW(DCM_EncapsulatedDocument));
@@ -1388,7 +1403,7 @@
     if (!GetTagValue(sop, DICOM_TAG_SOP_CLASS_UID) ||
         !GetTagValue(mime, FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument)) ||
         sop != UID_EncapsulatedPDFStorage ||
-        mime != "application/pdf")
+        mime != MIME_PDF)
     {
       return false;
     }
@@ -1470,16 +1485,16 @@
     switch (transferSyntax)
     {
       case EXS_JPEGProcess1:
-        mime = "image/jpeg";
+        mime = MIME_JPEG;
         break;
        
       case EXS_JPEG2000LosslessOnly:
       case EXS_JPEG2000:
-        mime = "image/jp2";
+        mime = MIME_JPEG2000;
         break;
 
       default:
-        mime = "application/octet-stream";
+        mime = MIME_BINARY;
         break;
     }
   }
--- a/Core/DicomParsing/ParsedDicomFile.h	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/DicomParsing/ParsedDicomFile.h	Tue Oct 30 11:55:23 2018 +0100
@@ -183,11 +183,8 @@
 
     void EmbedImage(const ImageAccessor& accessor);
 
-#if (ORTHANC_ENABLE_JPEG == 1 &&  \
-     ORTHANC_ENABLE_PNG == 1)
     void EmbedImage(const std::string& mime,
                     const std::string& content);
-#endif
 
     Encoding GetEncoding() const;
 
--- a/Core/Enumerations.h	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/Enumerations.h	Tue Oct 30 11:55:23 2018 +0100
@@ -47,6 +47,28 @@
 
 namespace Orthanc
 {
+  static const char* const URI_SCHEME_PREFIX_BINARY = "data:application/octet-stream;base64,";
+
+  static const char* const MIME_BINARY = "application/octet-stream";
+  static const char* const MIME_DICOM = "application/dicom";
+  static const char* const MIME_JPEG = "image/jpeg";
+  static const char* const MIME_JPEG2000 = "image/jp2";
+  static const char* const MIME_JSON = "application/json";
+  static const char* const MIME_PDF = "application/pdf";
+  static const char* const MIME_PNG = "image/png";
+  static const char* const MIME_XML = "application/xml";
+  static const char* const MIME_PLAIN_TEXT = "text/plain";
+
+  /**
+   * "No Internet Media Type (aka MIME type, content type) for PBM has
+   * been registered with IANA, but the unofficial value
+   * image/x-portable-arbitrarymap is assigned by this specification,
+   * to be consistent with conventional values for the older Netpbm
+   * formats."  http://netpbm.sourceforge.net/doc/pam.html
+   **/
+  static const char* const MIME_PAM = "image/x-portable-arbitrarymap";
+
+  
   enum Endianness
   {
     Endianness_Unknown,
--- a/Core/HttpServer/HttpFileSender.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/HttpServer/HttpFileSender.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -69,7 +69,7 @@
   {
     if (contentType_.empty())
     {
-      return "application/octet-stream";
+      return MIME_BINARY;
     }
     else
     {
--- a/Core/HttpServer/HttpOutput.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/HttpServer/HttpOutput.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -589,7 +589,7 @@
     std::string contentType = stream.GetContentType();
     if (contentType.empty())
     {
-      contentType = "application/octet-stream";
+      contentType = MIME_BINARY;
     }
 
     stateMachine_.SetContentType(contentType.c_str());
--- a/Core/RestApi/RestApi.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/RestApi/RestApi.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -197,12 +197,12 @@
         Toolbox::TokenizeString(accepted, it->second, ';');
         for (size_t i = 0; i < accepted.size(); i++)
         {
-          if (accepted[i] == "application/xml")
+          if (accepted[i] == MIME_XML)
           {
             wrappedOutput.SetConvertJsonToXml(true);
           }
 
-          if (accepted[i] == "application/json")
+          if (accepted[i] == MIME_JSON)
           {
             wrappedOutput.SetConvertJsonToXml(false);
           }
--- a/Core/RestApi/RestApiOutput.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/RestApi/RestApiOutput.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -96,7 +96,10 @@
 #if ORTHANC_ENABLE_PUGIXML == 1
       std::string s;
       Toolbox::JsonToXml(s, value);
-      output_.SetContentType("application/xml; charset=utf-8");
+
+      std::string mime = std::string(MIME_XML) + "; charset=utf-8";
+      output_.SetContentType(mime.c_str());
+      
       output_.Answer(s);
 #else
       LOG(ERROR) << "Orthanc was compiled without XML support";
@@ -105,8 +108,10 @@
     }
     else
     {
+      std::string mime = std::string(MIME_JSON) + "; charset=utf-8";
+      output_.SetContentType(mime.c_str());
+      
       Json::StyledWriter writer;
-      output_.SetContentType("application/json; charset=utf-8");
       output_.Answer(writer.write(value));
     }
 
--- a/Core/Toolbox.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/Core/Toolbox.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -328,11 +328,11 @@
       // http://en.wikipedia.org/wiki/Mime_types
       // Text types
       if (!strcmp(extension, "txt"))
-        contentType = "text/plain";
+        contentType = MIME_PLAIN_TEXT;
       else if (!strcmp(extension, "html"))
         contentType = "text/html";
       else if (!strcmp(extension, "xml"))
-        contentType = "text/xml";
+        contentType = MIME_XML;
       else if (!strcmp(extension, "css"))
         contentType = "text/css";
 
@@ -340,19 +340,21 @@
       else if (!strcmp(extension, "js"))
         contentType = "application/javascript";
       else if (!strcmp(extension, "json"))
-        contentType = "application/json";
+        contentType = MIME_JSON;
       else if (!strcmp(extension, "pdf"))
-        contentType = "application/pdf";
+        contentType = MIME_PDF;
       else if (!strcmp(extension, "wasm"))
         contentType = "application/wasm";
 
       // Images types
       else if (!strcmp(extension, "jpg") || !strcmp(extension, "jpeg"))
-        contentType = "image/jpeg";
+        contentType = MIME_JPEG;
       else if (!strcmp(extension, "gif"))
         contentType = "image/gif";
       else if (!strcmp(extension, "png"))
-        contentType = "image/png";
+        contentType = MIME_PNG;
+      else if (!strcmp(extension, "pam"))
+        contentType = MIME_PAM;
     }
 
     return contentType;
--- a/OrthancServer/OrthancInitialization.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancInitialization.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -336,7 +336,7 @@
       for (size_t i = 0; i < members.size(); i++)
       {
         const std::string& name = members[i];
-        std::string mime = "application/octet-stream";
+        std::string mime = MIME_BINARY;
 
         const Json::Value& value = parameter[name];
         int contentType;
--- a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -88,14 +88,14 @@
   {
     OrthancRestApi::GetApi(call).leaveBarrier_ = true;
     OrthancRestApi::GetApi(call).resetRequestReceived_ = true;
-    call.GetOutput().AnswerBuffer("{}", "application/json");
+    call.GetOutput().AnswerBuffer("{}", MIME_JSON);
   }
 
 
   void OrthancRestApi::ShutdownOrthanc(RestApiPostCall& call)
   {
     OrthancRestApi::GetApi(call).leaveBarrier_ = true;
-    call.GetOutput().AnswerBuffer("{}", "application/json");
+    call.GetOutput().AnswerBuffer("{}", MIME_JSON);
     LOG(WARNING) << "Shutdown request received";
   }
 
--- a/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -98,7 +98,7 @@
   static void DeleteChanges(RestApiDeleteCall& call)
   {
     OrthancRestApi::GetIndex(call).DeleteChanges();
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
@@ -130,7 +130,7 @@
   static void DeleteExports(RestApiDeleteCall& call)
   {
     OrthancRestApi::GetIndex(call).DeleteExportedResources();
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
   
 
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -67,7 +67,7 @@
       if (connection.Echo())
       {
         // Echo has succeeded
-        call.GetOutput().AnswerBuffer("{}", "application/json");
+        call.GetOutput().AnswerBuffer("{}", MIME_JSON);
         return;
       }
     }
@@ -589,14 +589,14 @@
   static void GetQueryLevel(RestApiGetCall& call)
   {
     QueryAccessor query(call);
-    call.GetOutput().AnswerBuffer(EnumerationToString(query.GetHandler().GetLevel()), "text/plain");
+    call.GetOutput().AnswerBuffer(EnumerationToString(query.GetHandler().GetLevel()), MIME_PLAIN_TEXT);
   }
 
 
   static void GetQueryModality(RestApiGetCall& call)
   {
     QueryAccessor query(call);
-    call.GetOutput().AnswerBuffer(query.GetHandler().GetModalitySymbolicName(), "text/plain");
+    call.GetOutput().AnswerBuffer(query.GetHandler().GetModalitySymbolicName(), MIME_PLAIN_TEXT);
   }
 
 
@@ -604,7 +604,7 @@
   {
     ServerContext& context = OrthancRestApi::GetContext(call);
     context.GetQueryRetrieveArchive().Remove(call.GetUriComponent("id", ""));
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
@@ -798,7 +798,7 @@
     }
 
     // Move has succeeded
-    call.GetOutput().AnswerBuffer("{}", "application/json");
+    call.GetOutput().AnswerBuffer("{}", MIME_JSON);
   }
 
 
@@ -958,7 +958,7 @@
       RemoteModalityParameters modality;
       modality.Unserialize(json);
       Configuration::UpdateModality(context, call.GetUriComponent("id", ""), modality);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
   }
 
@@ -968,7 +968,7 @@
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     Configuration::RemoveModality(context, call.GetUriComponent("id", ""));
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
@@ -983,7 +983,7 @@
       WebServiceParameters peer;
       peer.Unserialize(json);
       Configuration::UpdatePeer(context, call.GetUriComponent("id", ""), peer);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
   }
 
@@ -993,7 +993,7 @@
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     Configuration::RemovePeer(context, call.GetUriComponent("id", ""));
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -201,7 +201,7 @@
   {
     std::string publicId = call.GetUriComponent("id", "");
     bool isProtected = OrthancRestApi::GetIndex(call).IsProtectedPatient(publicId);
-    call.GetOutput().AnswerBuffer(isProtected ? "1" : "0", "text/plain");
+    call.GetOutput().AnswerBuffer(isProtected ? "1" : "0", MIME_PLAIN_TEXT);
   }
 
 
@@ -218,12 +218,12 @@
     if (body == "0")
     {
       context.GetIndex().SetProtectedPatient(publicId, false);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
     else if (body == "1")
     {
       context.GetIndex().SetProtectedPatient(publicId, true);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
     else
     {
@@ -256,7 +256,7 @@
     call.BodyToString(target);
     SystemToolbox::WriteFile(dicom, target);
 
-    call.GetOutput().AnswerBuffer("{}", "application/json");
+    call.GetOutput().AnswerBuffer("{}", MIME_JSON);
   }
 
 
@@ -284,7 +284,7 @@
       // is present
       std::string full;
       context.ReadDicomAsJson(full, publicId);
-      call.GetOutput().AnswerBuffer(full, "application/json");
+      call.GetOutput().AnswerBuffer(full, MIME_JSON);
     }
   }
 
@@ -360,27 +360,19 @@
 
       void EncodeUsingPng()
       {
-        format_ = "image/png";
+        format_ = MIME_PNG;
         DicomImageDecoder::ExtractPngImage(answer_, image_, mode_, invert_);
       }
 
       void EncodeUsingPam()
       {
-        /**
-         * "No Internet Media Type (aka MIME type, content type) for
-         * PBM has been registered with IANA, but the unofficial value
-         * image/x-portable-arbitrarymap is assigned by this
-         * specification, to be consistent with conventional values
-         * for the older Netpbm formats."
-         * http://netpbm.sourceforge.net/doc/pam.html
-         **/
-        format_ = "image/x-portable-arbitrarymap";
+        format_ = MIME_PAM;
         DicomImageDecoder::ExtractPamImage(answer_, image_, mode_, invert_);
       }
 
       void EncodeUsingJpeg(uint8_t quality)
       {
-        format_ = "image/jpeg";
+        format_ = MIME_JPEG;
         DicomImageDecoder::ExtractJpegImage(answer_, image_, mode_, invert_, quality);
       }
     };
@@ -558,13 +550,13 @@
 
     HttpContentNegociation negociation;
     EncodePng png(image);
-    negociation.Register("image/png", png);
+    negociation.Register(MIME_PNG, png);
 
     EncodeJpeg jpeg(image, call);
-    negociation.Register("image/jpeg", jpeg);
+    negociation.Register(MIME_JPEG, jpeg);
 
     EncodePam pam(image);
-    negociation.Register("image/x-portable-arbitrarymap", pam);
+    negociation.Register(MIME_PAM, pam);
 
     if (negociation.Apply(call.GetHttpHeaders()))
     {
@@ -604,7 +596,7 @@
     std::string result;
     decoded->ToMatlabString(result);
 
-    call.GetOutput().AnswerBuffer(result, "text/plain");
+    call.GetOutput().AnswerBuffer(result, MIME_PLAIN_TEXT);
   }
 
 
@@ -717,7 +709,7 @@
     std::string value;
     if (OrthancRestApi::GetIndex(call).LookupMetadata(value, publicId, metadata))
     {
-      call.GetOutput().AnswerBuffer(value, "text/plain");
+      call.GetOutput().AnswerBuffer(value, MIME_PLAIN_TEXT);
     }
   }
 
@@ -733,7 +725,7 @@
     if (IsUserMetadata(metadata))  // It is forbidden to modify internal metadata
     {      
       OrthancRestApi::GetIndex(call).DeleteMetadata(publicId, metadata);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
     else
     {
@@ -757,7 +749,7 @@
     {
       // It is forbidden to modify internal metadata
       OrthancRestApi::GetIndex(call).SetMetadata(publicId, metadata, value);
-      call.GetOutput().AnswerBuffer("", "text/plain");
+      call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
     }
     else
     {
@@ -858,7 +850,7 @@
       // Return the raw data (possibly compressed), as stored on the filesystem
       std::string content;
       context.ReadAttachment(content, publicId, type, false);
-      call.GetOutput().AnswerBuffer(content, "application/octet-stream");
+      call.GetOutput().AnswerBuffer(content, MIME_BINARY);
     }
   }
 
@@ -868,7 +860,7 @@
     FileInfo info;
     if (GetAttachmentInfo(info, call))
     {
-      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedSize()), "text/plain");
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedSize()), MIME_PLAIN_TEXT);
     }
   }
 
@@ -878,7 +870,7 @@
     FileInfo info;
     if (GetAttachmentInfo(info, call))
     {
-      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedSize()), "text/plain");
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedSize()), MIME_PLAIN_TEXT);
     }
   }
 
@@ -889,7 +881,7 @@
     if (GetAttachmentInfo(info, call) &&
         info.GetUncompressedMD5() != "")
     {
-      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedMD5()), "text/plain");
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedMD5()), MIME_PLAIN_TEXT);
     }
   }
 
@@ -900,7 +892,7 @@
     if (GetAttachmentInfo(info, call) &&
         info.GetCompressedMD5() != "")
     {
-      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedMD5()), "text/plain");
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedMD5()), MIME_PLAIN_TEXT);
     }
   }
 
@@ -950,7 +942,7 @@
     if (ok)
     {
       LOG(INFO) << "The attachment " << name << " of resource " << publicId << " has the right MD5";
-      call.GetOutput().AnswerBuffer("{}", "application/json");
+      call.GetOutput().AnswerBuffer("{}", MIME_JSON);
     }
     else
     {
@@ -971,7 +963,7 @@
     if (IsUserContentType(contentType) &&  // It is forbidden to modify internal attachments
         context.AddAttachment(publicId, StringToContentType(name), call.GetBodyData(), call.GetBodySize()))
     {
-      call.GetOutput().AnswerBuffer("{}", "application/json");
+      call.GetOutput().AnswerBuffer("{}", MIME_JSON);
     }
     else
     {
@@ -1009,7 +1001,7 @@
     if (allowed) 
     {
       OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType);
-      call.GetOutput().AnswerBuffer("{}", "application/json");
+      call.GetOutput().AnswerBuffer("{}", MIME_JSON);
     }
     else
     {
@@ -1028,7 +1020,7 @@
     FileContentType contentType = StringToContentType(name);
 
     OrthancRestApi::GetContext(call).ChangeAttachmentCompression(publicId, contentType, compression);
-    call.GetOutput().AnswerBuffer("{}", "application/json");
+    call.GetOutput().AnswerBuffer("{}", MIME_JSON);
   }
 
 
@@ -1038,7 +1030,7 @@
     if (GetAttachmentInfo(info, call))
     {
       std::string answer = (info.GetCompressionType() == CompressionType_None) ? "0" : "1";
-      call.GetOutput().AnswerBuffer(answer, "text/plain");
+      call.GetOutput().AnswerBuffer(answer, MIME_PLAIN_TEXT);
     }
   }
 
@@ -1475,7 +1467,7 @@
 
     if (locker.GetDicom().ExtractPdf(pdf))
     {
-      call.GetOutput().AnswerBuffer(pdf, "application/pdf");
+      call.GetOutput().AnswerBuffer(pdf, MIME_PDF);
       return;
     }
   }
@@ -1537,7 +1529,7 @@
       }
     }
 
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
@@ -1546,7 +1538,7 @@
   {
     ServerContext& context = OrthancRestApi::GetContext(call);
     ServerToolbox::ReconstructResource(context, call.GetUriComponent("id", ""));
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
@@ -1563,7 +1555,7 @@
       ServerToolbox::ReconstructResource(context, *study);
     }
     
-    call.GetOutput().AnswerBuffer("", "text/plain");
+    call.GetOutput().AnswerBuffer("", MIME_PLAIN_TEXT);
   }
 
 
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -99,19 +99,19 @@
     std::string level = call.GetArgument("level", "");
     if (level == "patient")
     {
-      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient), "text/plain");
+      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient), MIME_PLAIN_TEXT);
     }
     else if (level == "study")
     {
-      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study), "text/plain");
+      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study), MIME_PLAIN_TEXT);
     }
     else if (level == "series")
     {
-      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series), "text/plain");
+      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series), MIME_PLAIN_TEXT);
     }
     else if (level == "instance")
     {
-      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance), "text/plain");
+      call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance), MIME_PLAIN_TEXT);
     }
   }
 
@@ -128,13 +128,13 @@
       lock.GetLua().Execute(result, command);
     }
 
-    call.GetOutput().AnswerBuffer(result, "text/plain");
+    call.GetOutput().AnswerBuffer(result, MIME_PLAIN_TEXT);
   }
 
   template <bool UTC>
   static void GetNowIsoString(RestApiGetCall& call)
   {
-    call.GetOutput().AnswerBuffer(SystemToolbox::GetNowIsoString(UTC), "text/plain");
+    call.GetOutput().AnswerBuffer(SystemToolbox::GetNowIsoString(UTC), MIME_PLAIN_TEXT);
   }
 
 
@@ -142,14 +142,14 @@
   {
     std::string statement;
     GetFileResource(statement, EmbeddedResources::DICOM_CONFORMANCE_STATEMENT);
-    call.GetOutput().AnswerBuffer(statement, "text/plain");
+    call.GetOutput().AnswerBuffer(statement, MIME_PLAIN_TEXT);
   }
 
 
   static void GetDefaultEncoding(RestApiGetCall& call)
   {
     Encoding encoding = GetDefaultDicomEncoding();
-    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), MIME_PLAIN_TEXT);
   }
 
 
@@ -159,7 +159,7 @@
 
     Configuration::SetDefaultEncoding(encoding);
 
-    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+    call.GetOutput().AnswerBuffer(EnumerationToString(encoding), MIME_PLAIN_TEXT);
   }
 
 
@@ -357,7 +357,7 @@
     
     if (ok)
     {
-      call.GetOutput().AnswerBuffer("{}", "application/json");
+      call.GetOutput().AnswerBuffer("{}", MIME_JSON);
     }
   }
 
--- a/OrthancServer/ServerEnumerations.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/OrthancServer/ServerEnumerations.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -176,13 +176,13 @@
     switch (type)
     {
       case FileContentType_Dicom:
-        return "application/dicom";
+        return MIME_DICOM;
 
       case FileContentType_DicomAsJson:
-        return "application/json";
+        return MIME_JSON;
 
       default:
-        return "application/octet-stream";
+        return MIME_BINARY;
     }
   }
 
--- a/UnitTestsSources/UnitTestsMain.cpp	Tue Oct 30 10:46:17 2018 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Tue Oct 30 11:55:23 2018 +0100
@@ -308,7 +308,7 @@
 
   ASSERT_EQ("text/plain", Toolbox::AutodetectMimeType("../NOTES.txt"));
   ASSERT_EQ("text/plain", Toolbox::AutodetectMimeType("../coucou.xml/NOTES.txt"));
-  ASSERT_EQ("text/xml", Toolbox::AutodetectMimeType("../.xml"));
+  ASSERT_EQ("application/xml", Toolbox::AutodetectMimeType("../.xml"));
 
   ASSERT_EQ("application/javascript", Toolbox::AutodetectMimeType("NOTES.js"));
   ASSERT_EQ("application/json", Toolbox::AutodetectMimeType("NOTES.json"));
@@ -316,7 +316,7 @@
   ASSERT_EQ("text/css", Toolbox::AutodetectMimeType("NOTES.css"));
   ASSERT_EQ("text/html", Toolbox::AutodetectMimeType("NOTES.html"));
   ASSERT_EQ("text/plain", Toolbox::AutodetectMimeType("NOTES.txt"));
-  ASSERT_EQ("text/xml", Toolbox::AutodetectMimeType("NOTES.xml"));
+  ASSERT_EQ("application/xml", Toolbox::AutodetectMimeType("NOTES.xml"));
   ASSERT_EQ("image/gif", Toolbox::AutodetectMimeType("NOTES.gif"));
   ASSERT_EQ("image/jpeg", Toolbox::AutodetectMimeType("NOTES.jpg"));
   ASSERT_EQ("image/jpeg", Toolbox::AutodetectMimeType("NOTES.jpeg"));