changeset 1112:a119f9ae3640

upgrade to Mongoose 3.8
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 01 Sep 2014 12:20:26 +0200
parents 929bf8c2123d
children ba5c0908600c
files CMakeLists.txt Core/HttpServer/MongooseServer.cpp NEWS Resources/CMake/MongooseConfiguration.cmake Resources/Patches/mongoose-3.8-patch.diff
diffstat 5 files changed, 270 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Mon Sep 01 11:23:13 2014 +0200
+++ b/CMakeLists.txt	Mon Sep 01 12:20:26 2014 +0200
@@ -44,6 +44,8 @@
 # Distribution-specific settings
 SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
 mark_as_advanced(USE_GTEST_DEBIAN_SOURCE_PACKAGE)
+SET(SYSTEM_MONGOOSE_USE_CALLBACKS ON CACHE BOOL "The system version of Mongoose uses callbacks (version >= 3.7)")
+mark_as_advanced(SYSTEM_MONGOOSE_USE_CALLBACKS)
 
 # Path to the root folder of the Orthanc distribution
 set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR})
--- a/Core/HttpServer/MongooseServer.cpp	Mon Sep 01 11:23:13 2014 +0200
+++ b/Core/HttpServer/MongooseServer.cpp	Mon Sep 01 12:20:26 2014 +0200
@@ -547,191 +547,215 @@
   }
 
 
+  static void InternalCallback(struct mg_connection *connection,
+                               const struct mg_request_info *request)
+  {
+    MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
+    MongooseOutputStream stream(connection);
+    HttpOutput output(stream);
 
+    // Check remote calls
+    if (!that->IsRemoteAccessAllowed() &&
+        request->remote_ip != LOCALHOST)
+    {
+      output.SendUnauthorized(ORTHANC_REALM);
+      return;
+    }
+
+
+    // Extract the HTTP headers
+    HttpHandler::Arguments headers;
+    for (int i = 0; i < request->num_headers; i++)
+    {
+      std::string name = request->http_headers[i].name;
+      std::transform(name.begin(), name.end(), name.begin(), ::tolower);
+      headers.insert(std::make_pair(name, request->http_headers[i].value));
+    }
+
+
+    // Extract the GET arguments
+    HttpHandler::Arguments argumentsGET;
+    if (!strcmp(request->request_method, "GET"))
+    {
+      HttpHandler::ParseGetArguments(argumentsGET, request->query_string);
+    }
+
+
+    // Compute the HTTP method, taking method faking into consideration
+    HttpMethod method;
+    if (!ExtractMethod(method, request, headers, argumentsGET))
+    {
+      output.SendHeader(HttpStatus_400_BadRequest);
+      return;
+    }
+
+
+    // Authenticate this connection
+    if (that->IsAuthenticationEnabled() &&
+        !Authorize(*that, headers, output))
+    {
+      return;
+    }
+
+
+    // Apply the filter, if it is installed
+    const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter();
+    if (filter != NULL)
+    {
+      std::string username = GetAuthenticatedUsername(headers);
+
+      char remoteIp[24];
+      sprintf(remoteIp, "%d.%d.%d.%d", 
+              reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], 
+              reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], 
+              reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], 
+              reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]);
+
+      if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str()))
+      {
+        output.SendUnauthorized(ORTHANC_REALM);
+        return;
+      }
+    }
+
+
+    // Extract the body of the request for PUT and POST
+    std::string body;
+    if (method == HttpMethod_Post ||
+        method == HttpMethod_Put)
+    {
+      PostDataStatus status;
+
+      HttpHandler::Arguments::const_iterator ct = headers.find("content-type");
+      if (ct == headers.end())
+      {
+        // No content-type specified. Assume no multi-part content occurs at this point.
+        status = ReadBody(body, connection, headers);          
+      }
+      else
+      {
+        std::string contentType = ct->second;
+        if (contentType.size() >= multipartLength &&
+            !memcmp(contentType.c_str(), multipart, multipartLength))
+        {
+          status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore());
+        }
+        else
+        {
+          status = ReadBody(body, connection, headers);
+        }
+      }
+
+      switch (status)
+      {
+        case PostDataStatus_NoLength:
+          output.SendHeader(HttpStatus_411_LengthRequired);
+          return;
+
+        case PostDataStatus_Failure:
+          output.SendHeader(HttpStatus_400_BadRequest);
+          return;
+
+        case PostDataStatus_Pending:
+          output.AnswerBufferWithContentType(NULL, 0, "");
+          return;
+
+        default:
+          break;
+      }
+    }
+
+
+    // Decompose the URI into its components
+    UriComponents uri;
+    try
+    {
+      Toolbox::SplitUriComponents(uri, request->uri);
+    }
+    catch (OrthancException)
+    {
+      output.SendHeader(HttpStatus_400_BadRequest);
+      return;
+    }
+
+
+    // Loop over the candidate handlers for this URI
+    LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
+    bool found = false;
+
+    for (MongooseServer::Handlers::const_iterator it = 
+           that->GetHandlers().begin(); it != that->GetHandlers().end() && !found; ++it) 
+    {
+      try
+      {
+        found = (*it)->Handle(output, method, uri, headers, argumentsGET, body);
+      }
+      catch (OrthancException& e)
+      {
+        // Using this candidate handler results in an exception
+        LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
+        return;
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast";
+        return;
+      }
+      catch (std::runtime_error&)
+      {
+        LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request";
+        return;
+      }
+    }
+
+    if (!found)
+    {
+      try
+      {
+        output.SendHeader(HttpStatus_404_NotFound);
+      }
+      catch (OrthancException&)
+      {
+      }
+    }
+  }
+
+
+#if MONGOOSE_USE_CALLBACKS == 0
   static void* Callback(enum mg_event event,
                         struct mg_connection *connection,
                         const struct mg_request_info *request)
   {
     if (event == MG_NEW_REQUEST) 
     {
-      MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
-      MongooseOutputStream stream(connection);
-      HttpOutput output(stream);
-
-      // Check remote calls
-      if (!that->IsRemoteAccessAllowed() &&
-          request->remote_ip != LOCALHOST)
-      {
-        output.SendUnauthorized(ORTHANC_REALM);
-        return (void*) "";
-      }
-
-
-      // Extract the HTTP headers
-      HttpHandler::Arguments headers;
-      for (int i = 0; i < request->num_headers; i++)
-      {
-        std::string name = request->http_headers[i].name;
-        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
-        headers.insert(std::make_pair(name, request->http_headers[i].value));
-      }
-
-
-      // Extract the GET arguments
-      HttpHandler::Arguments argumentsGET;
-      if (!strcmp(request->request_method, "GET"))
-      {
-        HttpHandler::ParseGetArguments(argumentsGET, request->query_string);
-      }
-
-
-      // Compute the HTTP method, taking method faking into consideration
-      HttpMethod method;
-      if (!ExtractMethod(method, request, headers, argumentsGET))
-      {
-        output.SendHeader(HttpStatus_400_BadRequest);
-        return (void*) "";
-      }
-
-
-      // Authenticate this connection
-      if (that->IsAuthenticationEnabled() &&
-          !Authorize(*that, headers, output))
-      {
-        return (void*) "";
-      }
-
-
-      // Apply the filter, if it is installed
-      const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter();
-      if (filter != NULL)
-      {
-        std::string username = GetAuthenticatedUsername(headers);
-
-        char remoteIp[24];
-        sprintf(remoteIp, "%d.%d.%d.%d", 
-                reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], 
-                reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], 
-                reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], 
-                reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]);
-
-        if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str()))
-        {
-          output.SendUnauthorized(ORTHANC_REALM);
-          return (void*) "";
-        }
-      }
-
-
-      // Extract the body of the request for PUT and POST
-      std::string body;
-      if (method == HttpMethod_Post ||
-          method == HttpMethod_Put)
-      {
-        PostDataStatus status;
-
-        HttpHandler::Arguments::const_iterator ct = headers.find("content-type");
-        if (ct == headers.end())
-        {
-          // No content-type specified. Assume no multi-part content occurs at this point.
-          status = ReadBody(body, connection, headers);          
-        }
-        else
-        {
-          std::string contentType = ct->second;
-          if (contentType.size() >= multipartLength &&
-              !memcmp(contentType.c_str(), multipart, multipartLength))
-          {
-            status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore());
-          }
-          else
-          {
-            status = ReadBody(body, connection, headers);
-          }
-        }
-
-        switch (status)
-        {
-          case PostDataStatus_NoLength:
-            output.SendHeader(HttpStatus_411_LengthRequired);
-            return (void*) "";
-
-          case PostDataStatus_Failure:
-            output.SendHeader(HttpStatus_400_BadRequest);
-            return (void*) "";
-
-          case PostDataStatus_Pending:
-            output.AnswerBufferWithContentType(NULL, 0, "");
-            return (void*) "";
-
-          default:
-            break;
-        }
-      }
-
-
-      // Decompose the URI into its components
-      UriComponents uri;
-      try
-      {
-        Toolbox::SplitUriComponents(uri, request->uri);
-      }
-      catch (OrthancException)
-      {
-        output.SendHeader(HttpStatus_400_BadRequest);
-        return (void*) "";
-      }
-
-
-      // Loop over the candidate handlers for this URI
-      LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
-      bool found = false;
-
-      for (MongooseServer::Handlers::const_iterator it = 
-             that->GetHandlers().begin(); it != that->GetHandlers().end() && !found; ++it) 
-      {
-        try
-        {
-          found = (*it)->Handle(output, method, uri, headers, argumentsGET, body);
-        }
-        catch (OrthancException& e)
-        {
-          // Using this candidate handler results in an exception
-          LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
-          return (void*) "";
-        }
-        catch (boost::bad_lexical_cast&)
-        {
-          LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast";
-          return (void*) "";
-        }
-        catch (std::runtime_error&)
-        {
-          LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request";
-          return (void*) "";
-        }
-      }
-
-      if (!found)
-      {
-        try
-        {
-          output.SendHeader(HttpStatus_404_NotFound);
-        }
-        catch (OrthancException&)
-        {
-        }
-      }
+      InternalCallback(connection, request);
 
       // Mark as processed
       return (void*) "";
-    } 
-    else 
+    }
+    else
     {
       return NULL;
     }
   }
 
+#elif MONGOOSE_USE_CALLBACKS == 1
+  static int Callback(struct mg_connection *connection)
+  {
+    struct mg_request_info *request = mg_get_request_info(connection);
+
+    InternalCallback(connection, request);
+
+    return 1;  // Do not let Mongoose handle the request by itself
+  }
+
+#else
+#error Please set MONGOOSE_USE_CALLBACKS
+#endif
+
+
+
+
 
   bool MongooseServer::IsRunning() const
   {
@@ -798,7 +822,19 @@
         NULL
       };
 
+#if MONGOOSE_USE_CALLBACKS == 0
       pimpl_->context_ = mg_start(&Callback, this, options);
+
+#elif MONGOOSE_USE_CALLBACKS == 1
+      struct mg_callbacks callbacks;
+      memset(&callbacks, 0, sizeof(callbacks));
+      callbacks.begin_request = Callback;
+      pimpl_->context_ = mg_start(&callbacks, this, options);
+
+#else
+#error Please set MONGOOSE_USE_CALLBACKS
+#endif
+
       if (!pimpl_->context_)
       {
         throw OrthancException("Unable to launch the Mongoose server");
--- a/NEWS	Mon Sep 01 11:23:13 2014 +0200
+++ b/NEWS	Mon Sep 01 12:20:26 2014 +0200
@@ -1,6 +1,9 @@
 Pending changes in the mainline
 ===============================
 
+* Upgrade to Mongoose 3.8 (the last release under the MIT license)
+* Fixes for Visual Studio 2013 and Visual Studio 64bit
+
 
 Version 0.8.2 (2014/08/07)
 ==========================
--- a/Resources/CMake/MongooseConfiguration.cmake	Mon Sep 01 11:23:13 2014 +0200
+++ b/Resources/CMake/MongooseConfiguration.cmake	Mon Sep 01 12:20:26 2014 +0200
@@ -1,13 +1,30 @@
 if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE)
   SET(MONGOOSE_SOURCES_DIR ${CMAKE_BINARY_DIR}/mongoose)
-  DownloadPackage(
-    "e718fc287b4eb1bd523be3fa00942bb0"
-    "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.1.tgz"
-    "${MONGOOSE_SOURCES_DIR}")
+
+  if (0)
+    # Use Mongoose 3.1
+    DownloadPackage(
+      "e718fc287b4eb1bd523be3fa00942bb0"
+      "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.1.tgz"
+      "${MONGOOSE_SOURCES_DIR}")
+    
+    add_definitions(-DMONGOOSE_USE_CALLBACKS=0)
+    set(MONGOOSE_PATCH ${ORTHANC_ROOT}/Resources/Patches/mongoose-3.1-patch.diff)
+
+  else() 
+    # Use Mongoose 3.8
+    DownloadPackage(
+      "7e3296295072792cdc3c633f9404e0c3"
+      "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.8.tgz"
+      "${MONGOOSE_SOURCES_DIR}")
+    
+    add_definitions(-DMONGOOSE_USE_CALLBACKS=1)
+    set(MONGOOSE_PATCH ${ORTHANC_ROOT}/Resources/Patches/mongoose-3.8-patch.diff)
+  endif()
 
   # Patch mongoose
   execute_process(
-    COMMAND patch mongoose.c ${ORTHANC_ROOT}/Resources/Patches/mongoose-3.1-patch.diff
+    COMMAND patch mongoose.c ${MONGOOSE_PATCH}
     WORKING_DIRECTORY ${MONGOOSE_SOURCES_DIR}
     )
 
@@ -56,5 +73,13 @@
     message(FATAL_ERROR "Please install the mongoose-devel package")
   endif()
 
+  if (SYSTEM_MONGOOSE_USE_CALLBACKS)
+    add_definitions(-DMONGOOSE_USE_CALLBACKS=1)
+  else()
+    add_definitions(-DMONGOOSE_USE_CALLBACKS=0)
+  endif()
+
   link_libraries(mongoose)
 endif()
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Patches/mongoose-3.8-patch.diff	Mon Sep 01 12:20:26 2014 +0200
@@ -0,0 +1,29 @@
+--- mongoose.c.orig	2014-09-01 11:25:18.223466994 +0200
++++ mongoose.c	2014-09-01 11:30:21.807479338 +0200
+@@ -50,6 +50,14 @@
+ #define PATH_MAX FILENAME_MAX
+ #endif // __SYMBIAN32__
+ 
++#if __gnu_hurd__ == 1
++/**
++ * There is no limit on the length on a path under GNU Hurd, so we set
++ * it to an arbitrary constant.
++ **/
++#define PATH_MAX 4096
++#endif
++
+ #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
+ #include <sys/types.h>
+ #include <sys/stat.h>
+@@ -108,8 +116,9 @@
+ #define strtoll(x, y, z) _atoi64(x)
+ #else
+ #define __func__  __FUNCTION__
+-#define strtoull(x, y, z) _strtoui64(x, y, z)
+-#define strtoll(x, y, z) _strtoi64(x, y, z)
++#include <stdlib.h>
++//#define strtoull(x, y, z) _strtoui64(x, y, z)
++//#define strtoll(x, y, z) _strtoi64(x, y, z)
+ #endif // _MSC_VER
+ 
+ #define ERRNO   GetLastError()