comparison PalanthirCppClient/HttpClient.cpp @ 45:33d67e1ab173

r
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Sep 2012 13:24:59 +0200
parents PalantirCppClient/HttpClient.cpp@9be852ad33d2
children a15e90e5d6fc
comparison
equal deleted inserted replaced
43:9be852ad33d2 45:33d67e1ab173
1 /**
2 * Palantir - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012 Medical Physics Department, CHU of Liege,
4 * Belgium
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 **/
26
27
28 #include "HttpClient.h"
29
30 #include <string.h>
31 #include <curl/curl.h>
32
33
34 namespace Palantir
35 {
36 struct HttpClient::PImpl
37 {
38 CURL* curl_;
39 struct curl_slist *postHeaders_;
40 };
41
42
43 static CURLcode CheckCode(CURLcode code)
44 {
45 if (code != CURLE_OK)
46 {
47 printf("ICI: %s\n", curl_easy_strerror(code));
48 throw HttpException("CURL: " + std::string(curl_easy_strerror(code)));
49 }
50
51 return code;
52 }
53
54
55 static size_t CurlCallback(void *buffer, size_t size, size_t nmemb, void *payload)
56 {
57 std::string& target = *(static_cast<std::string*>(payload));
58
59 size_t length = size * nmemb;
60 if (length == 0)
61 return 0;
62
63 size_t pos = target.size();
64
65 target.resize(pos + length);
66 memcpy(&target.at(pos), buffer, length);
67
68 return length;
69 }
70
71
72 HttpClient::HttpClient() : pimpl_(new PImpl)
73 {
74 pimpl_->postHeaders_ = NULL;
75 if ((pimpl_->postHeaders_ = curl_slist_append(pimpl_->postHeaders_, "Expect:")) == NULL)
76 {
77 throw HttpException("HttpClient: Not enough memory");
78 }
79
80 pimpl_->curl_ = curl_easy_init();
81 if (!pimpl_->curl_)
82 {
83 curl_slist_free_all(pimpl_->postHeaders_);
84 throw HttpException("HttpClient: Not enough memory");
85 }
86
87 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEFUNCTION, &CurlCallback));
88 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0));
89 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1));
90
91 #if PALANTIR_SSL_ENABLED == 1
92 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0));
93 #endif
94
95 url_ = "";
96 method_ = Palantir_HttpMethod_Get;
97 lastStatus_ = Palantir_HttpStatus_200_Ok;
98 isVerbose_ = false;
99 }
100
101
102 HttpClient::~HttpClient()
103 {
104 curl_easy_cleanup(pimpl_->curl_);
105 curl_slist_free_all(pimpl_->postHeaders_);
106 }
107
108
109 void HttpClient::SetVerbose(bool isVerbose)
110 {
111 isVerbose_ = isVerbose;
112
113 if (isVerbose_)
114 {
115 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 1));
116 }
117 else
118 {
119 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 0));
120 }
121 }
122
123
124 bool HttpClient::Apply(std::string& answer)
125 {
126 answer.clear();
127 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str()));
128 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer));
129 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, NULL));
130
131 switch (method_)
132 {
133 case Palantir_HttpMethod_Get:
134 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 1L));
135 break;
136
137 case Palantir_HttpMethod_Post:
138 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 1L));
139 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->postHeaders_));
140
141 if (postData_.size() > 0)
142 {
143 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, postData_.c_str()));
144 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, postData_.size()));
145 }
146 else
147 {
148 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL));
149 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0));
150 }
151
152 break;
153
154 case Palantir_HttpMethod_Delete:
155 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 1L));
156 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "DELETE"));
157 break;
158
159 case Palantir_HttpMethod_Put:
160 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L));
161 break;
162
163 default:
164 throw HttpException("HttpClient: Internal error");
165 }
166
167 // Do the actual request
168 CheckCode(curl_easy_perform(pimpl_->curl_));
169
170 long status;
171 CheckCode(curl_easy_getinfo(pimpl_->curl_, CURLINFO_RESPONSE_CODE, &status));
172
173 if (status == 0)
174 {
175 // This corresponds to a call to an inexistent host
176 lastStatus_ = Palantir_HttpStatus_500_InternalServerError;
177 }
178 else
179 {
180 lastStatus_ = static_cast<Palantir_HttpStatus>(status);
181 }
182
183 return (status >= 200 && status < 300);
184 }
185
186
187 bool HttpClient::Apply(Json::Value& answer)
188 {
189 std::string s;
190 if (Apply(s))
191 {
192 Json::Reader reader;
193 return reader.parse(s, answer);
194 }
195 else
196 {
197 return false;
198 }
199 }
200 }