1 /**
2  * Orthanc - A Lightweight, RESTful DICOM Store
3  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4  * Department, University Hospital of Liege, Belgium
5  * Copyright (C) 2017-2021 Osimis S.A., Belgium
6  *
7  * This program is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program. If not, see
19  * <http://www.gnu.org/licenses/>.
20  **/
21 
22 
23 #pragma once
24 
25 #include "Enumerations.h"
26 #include "OrthancFramework.h"
27 #include "WebServiceParameters.h"
28 
29 #include <string>
30 #include <boost/noncopyable.hpp>
31 #include <boost/shared_ptr.hpp>
32 #include <json/value.h>
33 
34 #if !defined(ORTHANC_ENABLE_CURL)
35 #  error The macro ORTHANC_ENABLE_CURL must be defined
36 #endif
37 
38 #if ORTHANC_ENABLE_CURL != 1
39 #  error Support for curl is disabled, cannot use this file
40 #endif
41 
42 #if !defined(ORTHANC_ENABLE_SSL)
43 #  error The macro ORTHANC_ENABLE_SSL must be defined
44 #endif
45 
46 #if !defined(ORTHANC_ENABLE_PKCS11)
47 #  error The macro ORTHANC_ENABLE_PKCS11 must be defined
48 #endif
49 
50 
51 namespace Orthanc
52 {
53   class ORTHANC_PUBLIC HttpClient : public boost::noncopyable
54   {
55   public:
56     typedef std::map<std::string, std::string>  HttpHeaders;
57 
58     class IRequestBody : public boost::noncopyable
59     {
60     public:
~IRequestBody()61       virtual ~IRequestBody()
62       {
63       }
64 
65       virtual bool ReadNextChunk(std::string& chunk) = 0;
66     };
67 
68     class IAnswer : public boost::noncopyable
69     {
70     public:
~IAnswer()71       virtual ~IAnswer()
72       {
73       }
74 
75       virtual void AddHeader(const std::string& key,
76                              const std::string& value) = 0;
77 
78       virtual void AddChunk(const void* data,
79                             size_t size) = 0;
80     };
81 
82   private:
83     class CurlHeaders;
84     class CurlRequestBody;
85     class CurlAnswer;
86     class DefaultAnswer;
87     class GlobalParameters;
88 
89     struct PImpl;
90     boost::shared_ptr<PImpl> pimpl_;
91 
92     std::string url_;
93     std::string credentials_;
94     HttpMethod method_;
95     HttpStatus lastStatus_;
96     std::string body_;  // This only makes sense for POST and PUT requests
97     bool isVerbose_;
98     long timeout_;
99     std::string proxy_;
100     bool verifyPeers_;
101     std::string caCertificates_;
102     std::string clientCertificateFile_;
103     std::string clientCertificateKeyFile_;
104     std::string clientCertificateKeyPassword_;
105     bool pkcs11Enabled_;
106     bool headersToLowerCase_;
107     bool redirectionFollowed_;
108 
109     // New in Orthanc 1.9.3 to avoid memcpy()
110     bool        hasExternalBody_;
111     const void* externalBodyData_;
112     size_t      externalBodySize_;
113 
114     void Setup();
115 
116     void operator= (const HttpClient&);  // Assignment forbidden
117     HttpClient(const HttpClient& base);  // Copy forbidden
118 
119     bool ApplyInternal(CurlAnswer& answer);
120 
121     bool ApplyInternal(std::string& answerBody,
122                        HttpHeaders* answerHeaders);
123 
124     bool ApplyInternal(Json::Value& answerBody,
125                        HttpHeaders* answerHeaders);
126 
127   public:
128     HttpClient();
129 
130     HttpClient(const WebServiceParameters& service,
131                const std::string& uri);
132 
133     ~HttpClient();
134 
135     void SetUrl(const char* url);
136 
137     void SetUrl(const std::string& url);
138 
139     const std::string& GetUrl() const;
140 
141     void SetMethod(HttpMethod method);
142 
143     HttpMethod GetMethod() const;
144 
145     void SetTimeout(long seconds);
146 
147     long GetTimeout() const;
148 
149     void AssignBody(const std::string& data);
150 
151     void AssignBody(const void* data,
152                     size_t size);
153 
154     void SetBody(IRequestBody& body);
155 
156     // New in Orthanc 1.9.3: The "data" buffer must have a lifetime
157     // that is longer than the HttpClient object
158     void SetExternalBody(const void* data,
159                          size_t size);
160 
161     void SetExternalBody(const std::string& data);
162 
163     void ClearBody();
164 
165     void SetVerbose(bool isVerbose);
166 
167     bool IsVerbose() const;
168 
169     void AddHeader(const std::string& key,
170                    const std::string& value);
171 
172     void ClearHeaders();
173 
174     bool Apply(IAnswer& answer);
175 
176     bool Apply(std::string& answerBody);
177 
178     bool Apply(Json::Value& answerBody);
179 
180     bool Apply(std::string& answerBody,
181                HttpHeaders& answerHeaders);
182 
183     bool Apply(Json::Value& answerBody,
184                HttpHeaders& answerHeaders);
185 
186     HttpStatus GetLastStatus() const;
187 
188     void SetCredentials(const char* username,
189                         const char* password);
190 
191     void SetProxy(const std::string& proxy);
192 
193     void SetHttpsVerifyPeers(bool verify);
194 
195     bool IsHttpsVerifyPeers() const;
196 
197     void SetHttpsCACertificates(const std::string& certificates);
198 
199     const std::string& GetHttpsCACertificates() const;
200 
201     void SetClientCertificate(const std::string& certificateFile,
202                               const std::string& certificateKeyFile,
203                               const std::string& certificateKeyPassword);
204 
205     void SetPkcs11Enabled(bool enabled);
206 
207     bool IsPkcs11Enabled() const;
208 
209     const std::string& GetClientCertificateFile() const;
210 
211     const std::string& GetClientCertificateKeyFile() const;
212 
213     const std::string& GetClientCertificateKeyPassword() const;
214 
215     void SetConvertHeadersToLowerCase(bool lowerCase);
216 
217     bool IsConvertHeadersToLowerCase() const;
218 
219     void SetRedirectionFollowed(bool follow);
220 
221     bool IsRedirectionFollowed() const;
222 
223     static void GlobalInitialize();
224 
225     static void GlobalFinalize();
226 
227     static void InitializePkcs11(const std::string& module,
228                                  const std::string& pin,
229                                  bool verbose);
230 
231     static void ConfigureSsl(bool httpsVerifyPeers,
232                              const std::string& httpsCACertificates);
233 
234     static void SetDefaultVerbose(bool verbose);
235 
236     static void SetDefaultProxy(const std::string& proxy);
237 
238     static void SetDefaultTimeout(long timeout);
239 
240     void ApplyAndThrowException(IAnswer& answer);
241 
242     void ApplyAndThrowException(std::string& answerBody);
243 
244     void ApplyAndThrowException(Json::Value& answerBody);
245 
246     void ApplyAndThrowException(std::string& answerBody,
247                                 HttpHeaders& answerHeaders);
248 
249     void ApplyAndThrowException(Json::Value& answerBody,
250                                 HttpHeaders& answerHeaders);
251 
252     static void ThrowException(HttpStatus status);
253   };
254 }
255