# HG changeset patch # User Alain Mazy # Date 1699105598 -3600 # Node ID 3206537cbb5658791938b2cc4a4c5ee505c179e0 # Parent 62bb63346185877e902c8f7ca9dc029c0325cee2 HttpCompression: now disabled by default + only compress known compressible content types diff -r 62bb63346185 -r 3206537cbb56 NEWS --- a/NEWS Tue Oct 17 15:06:11 2023 +0200 +++ b/NEWS Sat Nov 04 14:46:38 2023 +0100 @@ -8,6 +8,16 @@ - Update to rebuild the cache of the DicomWeb plugin when updating to DicomWeb 1.15. - New trigger configuration: "DicomWebCacheChange" - Fixed reading the triggers configuration. +* HTTP Compression: + - The default value of the "HttpCompressionEnabled" is now false by default. This reduces + the Orthanc overall CPU usage and latency. This is suitable for setups with large + bandwidth network like LAN. + - When "HttpCompressionEnabled" is true, only the content that is clearly identified as + compressible is compressed (JSON, XML, HTML, text, ...). DICOM files are never + compressed over HTTP. In prior versions, all content types were compressed. + This notably greatly improve loading time of large DICOM + files through WADO-RS e.g in StoneViewer when working on large bandwidth networks. + - When "HttpCompressionEnabled" is true, content < 2KB are never compressed. REST API -------- diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/Enumerations.cpp --- a/OrthancFramework/Sources/Enumerations.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/Enumerations.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -35,26 +35,6 @@ namespace Orthanc { - static const char* const MIME_CSS = "text/css"; - static const char* const MIME_DICOM = "application/dicom"; - static const char* const MIME_GIF = "image/gif"; - static const char* const MIME_GZIP = "application/gzip"; - static const char* const MIME_HTML = "text/html"; - static const char* const MIME_JAVASCRIPT = "application/javascript"; - static const char* const MIME_JPEG2000 = "image/jp2"; - static const char* const MIME_NACL = "application/x-nacl"; - static const char* const MIME_PLAIN_TEXT = "text/plain"; - static const char* const MIME_PNACL = "application/x-pnacl"; - static const char* const MIME_SVG = "image/svg+xml"; - static const char* const MIME_WEB_ASSEMBLY = "application/wasm"; - static const char* const MIME_WOFF = "application/x-font-woff"; - static const char* const MIME_WOFF2 = "font/woff2"; - static const char* const MIME_XML_2 = "text/xml"; - static const char* const MIME_ZIP = "application/zip"; - static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json"; - static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml"; - static const char* const MIME_ICO = "image/x-icon"; - // This function is autogenerated by the script // "Resources/CodeGeneration/GenerateErrorCodes.py" const char* EnumerationToString(ErrorCode error) diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/Enumerations.h --- a/OrthancFramework/Sources/Enumerations.h Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/Enumerations.h Sat Nov 04 14:46:38 2023 +0100 @@ -47,6 +47,27 @@ static const char* const MIME_MTL = "model/mtl"; static const char* const MIME_STL = "model/stl"; + static const char* const MIME_CSS = "text/css"; + static const char* const MIME_DICOM = "application/dicom"; + static const char* const MIME_GIF = "image/gif"; + static const char* const MIME_GZIP = "application/gzip"; + static const char* const MIME_HTML = "text/html"; + static const char* const MIME_JAVASCRIPT = "application/javascript"; + static const char* const MIME_JPEG2000 = "image/jp2"; + static const char* const MIME_NACL = "application/x-nacl"; + static const char* const MIME_PLAIN_TEXT = "text/plain"; + static const char* const MIME_PNACL = "application/x-pnacl"; + static const char* const MIME_SVG = "image/svg+xml"; + static const char* const MIME_WEB_ASSEMBLY = "application/wasm"; + static const char* const MIME_WOFF = "application/x-font-woff"; + static const char* const MIME_WOFF2 = "font/woff2"; + static const char* const MIME_XML_2 = "text/xml"; + static const char* const MIME_ZIP = "application/zip"; + static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json"; + static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml"; + static const char* const MIME_ICO = "image/x-icon"; + + /** * "No Internet Media Type (aka MIME type, content type) for PBM has * been registered with IANA, but the unofficial value diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp --- a/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/HttpServer/FilesystemHttpHandler.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -153,7 +153,7 @@ { FilesystemHttpSender sender(p); sender.SetContentType(SystemToolbox::AutodetectMimeType(p.string())); - output.Answer(sender); // TODO COMPRESSION + output.Answer(sender); } else if (listDirectoryContent_ && fs::exists(p) && diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/HttpServer/HttpFileSender.cpp --- a/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpFileSender.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -53,7 +53,8 @@ if (contentType_.empty()) { - contentType_ = SystemToolbox::AutodetectMimeType(filename); + MimeType mimeType = SystemToolbox::AutodetectMimeType(filename); + contentType_ = EnumerationToString(mimeType); } } diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/HttpServer/HttpOutput.cpp --- a/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -30,6 +30,7 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../Toolbox.h" +#include "../SystemToolbox.h" #include #include @@ -51,6 +52,7 @@ unsigned int keepAliveTimeout) : stream_(stream), state_(State_WritingHeader), + isContentCompressible_(false), status_(HttpStatus_200_Ok), hasContentLength_(false), contentLength_(0), @@ -102,6 +104,17 @@ AddHeader("Content-Type", contentType); } + void HttpOutput::StateMachine::SetContentCompressible(bool isContentCompressible) + { + isContentCompressible_ = isContentCompressible; + } + + bool HttpOutput::StateMachine::IsContentCompressible() const + { + // We assume that all files that compress correctly (mainly JSON, XML) are clearly identified. + return isContentCompressible_; + } + void HttpOutput::StateMachine::SetContentFilename(const char* filename) { // TODO Escape double quotes @@ -275,13 +288,11 @@ HttpCompression HttpOutput::GetPreferredCompression(size_t bodySize) const { -#if 0 - // TODO Do not compress small files? - if (bodySize < 512) + // Do not compress small files since there is no real size benefit. + if (bodySize < 2048) { return HttpCompression_None; } -#endif // Prefer "gzip" over "deflate" if the choice is offered @@ -368,11 +379,13 @@ void HttpOutput::SetContentType(MimeType contentType) { stateMachine_.SetContentType(EnumerationToString(contentType)); + stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); } void HttpOutput::SetContentType(const std::string &contentType) { stateMachine_.SetContentType(contentType.c_str()); + stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); } void HttpOutput::SetContentFilename(const char *filename) @@ -442,7 +455,7 @@ HttpCompression compression = GetPreferredCompression(length); - if (compression == HttpCompression_None) + if (compression == HttpCompression_None || !IsContentCompressible()) { stateMachine_.SetContentLength(length); stateMachine_.SendBody(buffer, length); diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/HttpServer/HttpOutput.h --- a/OrthancFramework/Sources/HttpServer/HttpOutput.h Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/HttpServer/HttpOutput.h Sat Nov 04 14:46:38 2023 +0100 @@ -56,6 +56,7 @@ IHttpOutputStream& stream_; State state_; + bool isContentCompressible_; HttpStatus status_; bool hasContentLength_; uint64_t contentLength_; @@ -82,6 +83,8 @@ void SetContentType(const char* contentType); + void SetContentCompressible(bool isCompressible); + void SetContentFilename(const char* filename); void SetCookie(const std::string& cookie, @@ -110,6 +113,8 @@ return state_; } + bool IsContentCompressible() const; + void CheckHeadersCompatibilityWithMultipart() const; void StartStream(const std::string& contentType); @@ -139,6 +144,11 @@ bool IsGzipAllowed() const; + bool IsContentCompressible() const + { + return stateMachine_.IsContentCompressible(); + } + void SendStatus(HttpStatus status, const char* message, size_t messageSize); diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/SystemToolbox.cpp --- a/OrthancFramework/Sources/SystemToolbox.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -725,6 +725,52 @@ } } + bool SystemToolbox::IsContentCompressible(MimeType mime) + { + switch (mime) + { + case MimeType_Css: + case MimeType_Html: + case MimeType_JavaScript: + case MimeType_Json: + case MimeType_Pam: + case MimeType_Pdf: + case MimeType_PlainText: + case MimeType_WebAssembly: + case MimeType_Xml: + case MimeType_PrometheusText: + case MimeType_DicomWebJson: + case MimeType_DicomWebXml: + return true; + default: // for all other (JPEG, DICOM, binary, ...) + return false; + } + } + + bool SystemToolbox::IsContentCompressible(const std::string& contentType) + { + if (contentType.empty()) + { + return false; + } + + if (contentType.find(MIME_JSON) != std::string::npos || + contentType.find(MIME_XML) != std::string::npos || + contentType.find(MIME_DICOM_WEB_JSON) != std::string::npos || + contentType.find(MIME_DICOM_WEB_XML) != std::string::npos || + contentType.find(MIME_PDF) != std::string::npos || + contentType.find(MIME_CSS) != std::string::npos || + contentType.find(MIME_HTML) != std::string::npos || + contentType.find(MIME_JAVASCRIPT) != std::string::npos || + contentType.find(MIME_PLAIN_TEXT) != std::string::npos || + contentType.find(MIME_WEB_ASSEMBLY) != std::string::npos || + contentType.find(MIME_XML_2) != std::string::npos) + { + return true; + } + + return false; + } MimeType SystemToolbox::AutodetectMimeType(const std::string& path) { diff -r 62bb63346185 -r 3206537cbb56 OrthancFramework/Sources/SystemToolbox.h --- a/OrthancFramework/Sources/SystemToolbox.h Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancFramework/Sources/SystemToolbox.h Sat Nov 04 14:46:38 2023 +0100 @@ -108,6 +108,10 @@ static unsigned int GetHardwareConcurrency(); + static bool IsContentCompressible(MimeType mime); + + static bool IsContentCompressible(const std::string& contentType); + static MimeType AutodetectMimeType(const std::string& path); static void GetEnvironmentVariables(std::map& env); diff -r 62bb63346185 -r 3206537cbb56 OrthancServer/Resources/Configuration.json --- a/OrthancServer/Resources/Configuration.json Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancServer/Resources/Configuration.json Sat Nov 04 14:46:38 2023 +0100 @@ -125,7 +125,12 @@ // Enable HTTP compression to improve network bandwidth utilization, // at the expense of more computations on the server. Orthanc // supports the "gzip" and "deflate" HTTP encodings. - "HttpCompressionEnabled" : true, + // When working on a LAN or on localhost, you should typically set + // this configuration to false while when working on low-bandwidth, + // you should set it to true. + // Note in versions up to 1.12.1, the default value was "true" and is + // "false" since 1.12.2. + "HttpCompressionEnabled" : false, // Enable the publication of the content of the Orthanc server as a // WebDAV share (new in Orthanc 1.8.0). On the localhost, the WebDAV diff -r 62bb63346185 -r 3206537cbb56 OrthancServer/Sources/main.cpp --- a/OrthancServer/Sources/main.cpp Tue Oct 17 15:06:11 2023 +0200 +++ b/OrthancServer/Sources/main.cpp Sat Nov 04 14:46:38 2023 +0100 @@ -1031,7 +1031,7 @@ httpServer.SetRemoteAccessAllowed(lock.GetConfiguration().GetBooleanParameter("RemoteAccessAllowed", false)); httpServer.SetKeepAliveEnabled(lock.GetConfiguration().GetBooleanParameter("KeepAlive", defaultKeepAlive)); httpServer.SetKeepAliveTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("KeepAliveTimeout", 1)); - httpServer.SetHttpCompressionEnabled(lock.GetConfiguration().GetBooleanParameter("HttpCompressionEnabled", true)); + httpServer.SetHttpCompressionEnabled(lock.GetConfiguration().GetBooleanParameter("HttpCompressionEnabled", false)); httpServer.SetTcpNoDelay(lock.GetConfiguration().GetBooleanParameter("TcpNoDelay", true)); httpServer.SetRequestTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpRequestTimeout", 30));