changeset 908:e078ea944089 plugins

refactoring HttpOutput
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 19 Jun 2014 17:47:39 +0200
parents 9b8298234254
children ef71057d8b26
files CMakeLists.txt Core/HttpServer/BufferHttpSender.h Core/HttpServer/FilesystemHttpHandler.cpp Core/HttpServer/FilesystemHttpSender.cpp Core/HttpServer/HttpOutput.cpp Core/HttpServer/HttpOutput.h Core/HttpServer/HttpOutputStream.cpp Core/HttpServer/HttpOutputStream.h Core/HttpServer/MongooseServer.cpp OrthancServer/ParsedDicomFile.cpp OrthancServer/main.cpp Plugins/Engine/PluginsHttpHandler.cpp Plugins/Engine/PluginsHttpHandler.h Plugins/OrthancCPlugin/OrthancCPlugin.h
diffstat 14 files changed, 316 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Jun 19 14:28:43 2014 +0200
+++ b/CMakeLists.txt	Thu Jun 19 17:47:39 2014 +0200
@@ -81,6 +81,7 @@
   Core/HttpServer/FilesystemHttpHandler.cpp
   Core/HttpServer/HttpHandler.cpp
   Core/HttpServer/HttpOutput.cpp
+  Core/HttpServer/HttpOutputStream.cpp
   Core/HttpServer/MongooseServer.cpp
   Core/HttpServer/HttpFileSender.cpp
   Core/HttpServer/FilesystemHttpSender.cpp
--- a/Core/HttpServer/BufferHttpSender.h	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/BufferHttpSender.h	Thu Jun 19 17:47:39 2014 +0200
@@ -49,7 +49,9 @@
     virtual bool SendData(HttpOutput& output)
     {
       if (buffer_.size())
-        output.Send(&buffer_[0], buffer_.size());
+      {
+        output.SendBodyData(&buffer_[0], buffer_.size());
+      }
 
       return true;
     }
--- a/Core/HttpServer/FilesystemHttpHandler.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/FilesystemHttpHandler.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -56,15 +56,15 @@
     namespace fs = boost::filesystem;
 
     output.SendOkHeader("text/html", false, 0, NULL);
-    output.SendString("<html>");
-    output.SendString("  <body>");
-    output.SendString("    <h1>Subdirectories</h1>");
-    output.SendString("    <ul>");
+    output.SendBodyString("<html>");
+    output.SendBodyString("  <body>");
+    output.SendBodyString("    <h1>Subdirectories</h1>");
+    output.SendBodyString("    <ul>");
 
     if (uri.size() > 0)
     {
       std::string h = Toolbox::FlattenUri(uri) + "/..";
-      output.SendString("<li><a href=\"" + h + "\">..</a></li>");
+      output.SendBodyString("<li><a href=\"" + h + "\">..</a></li>");
     }
 
     fs::directory_iterator end;
@@ -78,12 +78,12 @@
 
       std::string h = Toolbox::FlattenUri(uri) + "/" + f;
       if (fs::is_directory(it->status()))
-        output.SendString("<li><a href=\"" + h + "\">" + f + "</a></li>");
+        output.SendBodyString("<li><a href=\"" + h + "\">" + f + "</a></li>");
     }      
 
-    output.SendString("    </ul>");      
-    output.SendString("    <h1>Files</h1>");
-    output.SendString("    <ul>");
+    output.SendBodyString("    </ul>");      
+    output.SendBodyString("    <h1>Files</h1>");
+    output.SendBodyString("    <ul>");
 
     for (fs::directory_iterator it(p) ; it != end; ++it)
     {
@@ -95,12 +95,12 @@
 
       std::string h = Toolbox::FlattenUri(uri) + "/" + f;
       if (fs::is_regular_file(it->status()))
-        output.SendString("<li><a href=\"" + h + "\">" + f + "</a></li>");
+        output.SendBodyString("<li><a href=\"" + h + "\">" + f + "</a></li>");
     }      
 
-    output.SendString("    </ul>");
-    output.SendString("  </body>");
-    output.SendString("</html>");
+    output.SendBodyString("    </ul>");
+    output.SendBodyString("  </body>");
+    output.SendBodyString("</html>");
   }
 
 
--- a/Core/HttpServer/FilesystemHttpSender.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/FilesystemHttpSender.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -73,7 +73,7 @@
       }
       else
       {
-        output.Send(&buffer[0], nbytes);
+        output.SendBodyData(&buffer[0], nbytes);
       }
     }
 
--- a/Core/HttpServer/HttpOutput.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/HttpOutput.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -42,14 +42,6 @@
 
 namespace Orthanc
 {
-  void HttpOutput::SendString(const std::string& s)
-  {
-    if (s.size() > 0)
-    {
-      Send(&s[0], s.size());
-    }
-  }
-
   void HttpOutput::PrepareOkHeader(Header& header,
                                    const char* contentType,
                                    bool hasContentLength,
@@ -87,49 +79,37 @@
 
   void HttpOutput::SendOkHeader(const Header& header)
   {
-    std::string s = "HTTP/1.1 200 OK\r\n";
+    stream_.SendHttpStatus(HttpStatus_200_Ok);
 
+    std::string s;
     for (Header::const_iterator 
            it = header.begin(); it != header.end(); ++it)
     {
       s += it->first + ": " + it->second + "\r\n";
     }
 
-    s += "\r\n";
-
-    Send(&s[0], s.size());
+    stream_.SendHeaderString(s);
   }
 
 
   void HttpOutput::SendMethodNotAllowedError(const std::string& allowed)
   {
-    std::string s = 
-      "HTTP/1.1 405 " + std::string(EnumerationToString(HttpStatus_405_MethodNotAllowed)) +
-      "\r\nAllow: " + allowed + 
-      "\r\n\r\n";
-    Send(&s[0], s.size());
+    stream_.SendHttpStatus(HttpStatus_405_MethodNotAllowed);
+    stream_.SendHeaderString("Allow: " + allowed + "\r\n");
   }
 
 
   void HttpOutput::SendHeader(HttpStatus status)
   {
     if (status == HttpStatus_200_Ok ||
+        status == HttpStatus_301_MovedPermanently ||
+        status == HttpStatus_401_Unauthorized ||
         status == HttpStatus_405_MethodNotAllowed)
     {
       throw OrthancException("Please use the dedicated methods to this HTTP status code in HttpOutput");
     }
     
-    SendHeaderInternal(status);
-  }
-
-
-  void HttpOutput::SendHeaderInternal(HttpStatus status)
-  {
-    std::string s = "HTTP/1.1 " + 
-      boost::lexical_cast<std::string>(status) +
-      " " + std::string(EnumerationToString(status)) +
-      "\r\n\r\n";
-    Send(&s[0], s.size());
+    stream_.SendHttpStatus(status);
   }
 
 
@@ -137,7 +117,7 @@
                                                const std::string& contentType)
   {
     SendOkHeader(contentType.c_str(), true, buffer.size(), NULL);
-    SendString(buffer);
+    SendBodyString(buffer);
   }
 
 
@@ -160,7 +140,7 @@
     PrepareOkHeader(header, contentType.c_str(), true, buffer.size(), NULL);
     PrepareCookies(header, cookies);
     SendOkHeader(header);
-    SendString(buffer);
+    SendBodyString(buffer);
   }
 
 
@@ -169,7 +149,7 @@
                                                const std::string& contentType)
   {
     SendOkHeader(contentType.c_str(), true, size, NULL);
-    Send(buffer, size);
+    SendBodyData(buffer, size);
   }
 
 
@@ -182,17 +162,21 @@
     PrepareOkHeader(header, contentType.c_str(), true, size, NULL);
     PrepareCookies(header, cookies);
     SendOkHeader(header);
-    Send(buffer, size);
+    SendBodyData(buffer, size);
   }
 
 
-
   void HttpOutput::Redirect(const std::string& path)
   {
-    std::string s = 
-      "HTTP/1.1 301 " + std::string(EnumerationToString(HttpStatus_301_MovedPermanently)) + 
-      "\r\nLocation: " + path +
-      "\r\n\r\n";
-    Send(&s[0], s.size());  
+    stream_.SendHttpStatus(HttpStatus_301_MovedPermanently);
+    stream_.SendHeaderString("Location: " + path + "\r\n");
   }
+
+
+  void HttpOutput::SendUnauthorized(const std::string& realm)
+  {
+    stream_.SendHttpStatus(HttpStatus_401_Unauthorized);
+    stream_.SendHeaderString("WWW-Authenticate: Basic realm=\"" + realm + "\"\r\n");
+  }
+
 }
--- a/Core/HttpServer/HttpOutput.h	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/HttpOutput.h	Thu Jun 19 17:47:39 2014 +0200
@@ -36,6 +36,7 @@
 #include <string>
 #include <stdint.h>
 #include "../Enumerations.h"
+#include "HttpOutputStream.h"
 #include "HttpHandler.h"
 
 namespace Orthanc
@@ -45,8 +46,6 @@
   private:
     typedef std::list< std::pair<std::string, std::string> >  Header;
 
-    void SendHeaderInternal(HttpStatus status);
-
     void PrepareOkHeader(Header& header,
                          const char* contentType,
                          bool hasContentLength,
@@ -58,19 +57,27 @@
     void PrepareCookies(Header& header,
                         const HttpHandler::Arguments& cookies);
 
+    HttpOutputStream& stream_;
+
   public:
-    virtual ~HttpOutput()
+    HttpOutput(HttpOutputStream& stream) : stream_(stream)
     {
     }
 
-    virtual void Send(const void* buffer, size_t length) = 0;
-
     void SendOkHeader(const char* contentType,
                       bool hasContentLength,
                       uint64_t contentLength,
                       const char* contentFilename);
 
-    void SendString(const std::string& s);
+    void SendBodyData(const void* buffer, size_t length)
+    {
+      stream_.SendBodyData(buffer, length);
+    }
+
+    void SendBodyString(const std::string& str)
+    {
+      stream_.SendBodyString(str);
+    }
 
     void SendMethodNotAllowedError(const std::string& allowed);
 
@@ -78,6 +85,8 @@
 
     void Redirect(const std::string& path);
 
+    void SendUnauthorized(const std::string& realm);
+
     // Higher-level constructs to send entire buffers ----------------------------
 
     void AnswerBufferWithContentType(const std::string& buffer,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/HttpServer/HttpOutputStream.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -0,0 +1,104 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege,
+ * Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "HttpOutputStream.h"
+
+#include "../OrthancException.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace Orthanc
+{
+  void HttpOutputStream::SendHttpStatus(HttpStatus status)
+  {
+    if (state_ != State_WaitingHttpStatus)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    OnHttpStatusReceived(status);
+    state_ = State_WritingHeader;
+
+    std::string s = "HTTP/1.1 " + 
+      boost::lexical_cast<std::string>(status) +
+      " " + std::string(EnumerationToString(status)) +
+      "\r\n";
+
+    SendHeader(&s[0], s.size());
+  }
+
+  void HttpOutputStream::SendHeaderData(const void* buffer, size_t length)
+  {
+    if (state_ != State_WritingHeader)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    SendHeader(buffer, length);
+  }
+
+  void HttpOutputStream::SendHeaderString(const std::string& str)
+  {
+    if (str.size() > 0)
+    {
+      SendHeaderData(&str[0], str.size());
+    }
+  }
+
+  void HttpOutputStream::SendBodyData(const void* buffer, size_t length)
+  {
+    if (state_ == State_WaitingHttpStatus)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    if (state_ == State_WritingHeader)
+    {
+      // Close the HTTP header before writing the body
+      SendHeader("\r\n", 2);
+      state_ = State_WritingBody;
+    }
+
+    if (length > 0)
+    {
+      SendBody(buffer, length);
+    }
+  }
+
+  void HttpOutputStream::SendBodyString(const std::string& str)
+  {
+    if (str.size() > 0)
+    {
+      SendBodyData(&str[0], str.size());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Core/HttpServer/HttpOutputStream.h	Thu Jun 19 17:47:39 2014 +0200
@@ -0,0 +1,83 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege,
+ * Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../Enumerations.h"
+
+#include <string>
+#include <boost/noncopyable.hpp>
+
+namespace Orthanc
+{
+  class HttpOutputStream : public boost::noncopyable
+  {
+  protected:
+    enum State
+    {
+      State_WaitingHttpStatus,
+      State_WritingHeader,      
+      State_WritingBody
+    };
+
+  private:
+    State state_;
+
+  protected:
+    virtual void OnHttpStatusReceived(HttpStatus status)
+    {
+    }
+
+    virtual void SendHeader(const void* buffer, size_t length) = 0;
+
+    virtual void SendBody(const void* buffer, size_t length) = 0;
+
+  public:
+    HttpOutputStream() : state_(State_WaitingHttpStatus)
+    {
+    }
+
+    virtual ~HttpOutputStream()
+    {
+    }
+
+    void SendHttpStatus(HttpStatus status);
+
+    void SendHeaderData(const void* buffer, size_t length);
+
+    void SendHeaderString(const std::string& str);
+
+    void SendBodyData(const void* buffer, size_t length);
+
+    void SendBodyString(const std::string& str);
+  };
+}
--- a/Core/HttpServer/MongooseServer.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/Core/HttpServer/MongooseServer.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -68,23 +68,29 @@
   namespace
   {
     // Anonymous namespace to avoid clashes between compilation modules
-    class MongooseOutput : public HttpOutput
+    class MongooseOutputStream : public HttpOutputStream
     {
     private:
       struct mg_connection* connection_;
 
-    public:
-      MongooseOutput(struct mg_connection* connection) : connection_(connection)
-      {
-      }
-
-      virtual void Send(const void* buffer, size_t length)
+    protected:
+      virtual void SendBody(const void* buffer, size_t length)
       {
         if (length > 0)
         {
           mg_write(connection_, buffer, length);
         }
       }
+
+      virtual void SendHeader(const void* buffer, size_t length)
+      {
+        SendBody(buffer, length);
+      }
+
+    public:
+      MongooseOutputStream(struct mg_connection* connection) : connection_(connection)
+      {
+      }
     };
 
 
@@ -404,15 +410,6 @@
   }
 
 
-  static void SendUnauthorized(HttpOutput& output)
-  {
-    std::string s = "HTTP/1.1 401 Unauthorized\r\n" 
-      "WWW-Authenticate: Basic realm=\"" ORTHANC_REALM "\""
-      "\r\n\r\n";
-    output.Send(&s[0], s.size());
-  }
-
-
   static bool Authorize(const MongooseServer& that,
                         const HttpHandler::Arguments& headers,
                         HttpOutput& output)
@@ -432,7 +429,7 @@
 
     if (!granted)
     {
-      SendUnauthorized(output);
+      output.SendUnauthorized(ORTHANC_REALM);
       return false;
     }
     else
@@ -559,13 +556,14 @@
     if (event == MG_NEW_REQUEST) 
     {
       MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
-      MongooseOutput output(connection);
+      MongooseOutputStream stream(connection);
+      HttpOutput output(stream);
 
       // Check remote calls
       if (!that->IsRemoteAccessAllowed() &&
           request->remote_ip != LOCALHOST)
       {
-        SendUnauthorized(output);
+        output.SendUnauthorized(ORTHANC_REALM);
         return (void*) "";
       }
 
@@ -620,7 +618,7 @@
 
         if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str()))
         {
-          SendUnauthorized(output);
+          output.SendUnauthorized(ORTHANC_REALM);
           return (void*) "";
         }
       }
@@ -689,12 +687,9 @@
       // Loop over the candidate handlers for this URI
       LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
       bool found = false;
-      bool isError = false;
-      HttpStatus errorStatus;
-      std::string errorDescription;
 
       for (MongooseServer::Handlers::const_iterator it = 
-             that->GetHandlers().begin(); it != that->GetHandlers().end(); ++it) 
+             that->GetHandlers().begin(); it != that->GetHandlers().end() && !found; ++it) 
       {
         try
         {
@@ -702,40 +697,27 @@
         }
         catch (OrthancException& e)
         {
-          // Using this candidate handler results in an exception, try
-          // another handler before failing
-          isError = true;
-          errorStatus = HttpStatus_500_InternalServerError;
-          errorDescription = e.What();
+          // Using this candidate handler results in an exception
+          LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
+          return (void*) "";
         }
         catch (boost::bad_lexical_cast&)
         {
-          isError = true;
-          errorStatus = HttpStatus_400_BadRequest;
-          errorDescription = "Bad lexical cast";
+          LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast";
+          return (void*) "";
         }
         catch (std::runtime_error&)
         {
-          isError = true;
-          errorStatus = HttpStatus_400_BadRequest;
-          errorDescription = "Presumably a bad JSON request";
+          LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request";
+          return (void*) "";
         }
       }
       
       if (!found)
       {
-        if (isError)
-        {
-          LOG(ERROR) << "Exception in the HTTP handler: " << errorDescription;
-          output.SendHeader(errorStatus);
-        }
-        else
-        {
-          output.SendHeader(HttpStatus_404_NotFound);
-        }
+        output.SendHeader(HttpStatus_404_NotFound);
       }
 
-
       // Mark as processed
       return (void*) "";
     } 
--- a/OrthancServer/ParsedDicomFile.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/OrthancServer/ParsedDicomFile.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -279,7 +279,7 @@
 
       if (cond.good())
       {
-        output.GetLowLevelOutput().Send(&buffer[0], nbytes);
+        output.GetLowLevelOutput().SendBodyData(&buffer[0], nbytes);
         offset += nbytes;
       }
       else
--- a/OrthancServer/main.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/OrthancServer/main.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -446,6 +446,7 @@
       httpServer.RegisterHandler(httpPlugins);
       httpServer.RegisterHandler(staticResources);
       httpServer.RegisterHandler(restApi);
+      httpPlugins.SetOrthancRestApi(restApi);
 
       // GO !!! Start the requested servers
       if (Configuration::GetGlobalBoolParameter("HttpServerEnabled", true))
--- a/Plugins/Engine/PluginsHttpHandler.cpp	Thu Jun 19 14:28:43 2014 +0200
+++ b/Plugins/Engine/PluginsHttpHandler.cpp	Thu Jun 19 17:47:39 2014 +0200
@@ -42,6 +42,39 @@
 
 namespace Orthanc
 {
+  namespace
+  {
+    // Anonymous namespace to avoid clashes between compilation modules
+    class StringHttpOutput : public HttpOutput
+    {
+    private:
+      std::string target_;
+
+    public:
+      const std::string& GetOutput() const
+      {
+        return target_;
+      }
+
+      virtual void SendHeaderData(const void* buffer, size_t length)
+      {
+      }
+
+      virtual void SendBodyData(const void* buffer, size_t length)
+      {
+        size_t pos = target_.size();
+        target_.resize(pos + length);
+
+        if (length > 0)
+        {
+          memcpy(&target_[pos], buffer, length);
+        }
+      }
+    };
+  }
+
+
+
   struct PluginsHttpHandler::PImpl
   {
     typedef std::pair<boost::regex*, OrthancPluginRestCallback> Callback;
@@ -49,8 +82,9 @@
 
     ServerContext& context_;
     Callbacks callbacks_;
+    OrthancRestApi* restApi_;
 
-    PImpl(ServerContext& context) : context_(context)
+    PImpl(ServerContext& context) : context_(context), restApi_(NULL)
     {
     }
   };
@@ -298,4 +332,10 @@
     }
   }
 
+
+  void PluginsHttpHandler::SetOrthancRestApi(OrthancRestApi& restApi)
+  {
+    pimpl_->restApi_ = &restApi;
+  }
+
 }
--- a/Plugins/Engine/PluginsHttpHandler.h	Thu Jun 19 14:28:43 2014 +0200
+++ b/Plugins/Engine/PluginsHttpHandler.h	Thu Jun 19 17:47:39 2014 +0200
@@ -35,6 +35,7 @@
 #include "PluginsManager.h"
 #include "../../Core/HttpServer/HttpHandler.h"
 #include "../../OrthancServer/ServerContext.h"
+#include "../../OrthancServer/OrthancRestApi/OrthancRestApi.h"
 
 #include <list>
 #include <boost/shared_ptr.hpp>
@@ -62,5 +63,7 @@
 
     virtual bool InvokeService(_OrthancPluginService service,
                                const void* parameters);
+
+    void SetOrthancRestApi(OrthancRestApi& restApi);
   };
 }
--- a/Plugins/OrthancCPlugin/OrthancCPlugin.h	Thu Jun 19 14:28:43 2014 +0200
+++ b/Plugins/OrthancCPlugin/OrthancCPlugin.h	Thu Jun 19 17:47:39 2014 +0200
@@ -297,7 +297,7 @@
 
 
   /**
-   * @brief Signature of a function that answers to a REST request.
+   * @brief Signature of a callback function that answers to a REST request.
    **/
   typedef int32_t (*OrthancPluginRestCallback) (
     OrthancPluginRestOutput* output,