6 #include "httpauth.hpp"
10 #include "streamcompress.hpp"
11 #include <curl/curl.h>
14 #include <boost/iostreams/categories.hpp>
15 #include <boost/iostreams/copy.hpp>
16 #include <boost/iostreams/stream.hpp>
17 #include <boost/iostreams/stream_buffer.hpp>
18 #include <boost/iostreams/filter/symmetric.hpp>
19 #include <boost/iostreams/filter/zlib.hpp>
20 #include <boost/iostreams/filtering_stream.hpp>
21 #include <boost/iostreams/device/back_inserter.hpp>
23 http_request::input_handler::~input_handler()
27 size_t http_request::input_handler::read_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
29 if(reinterpret_cast<http_request::input_handler
*>(userdata
)->canceled
) return CURL_READFUNC_ABORT
;
31 return reinterpret_cast<http_request::input_handler
*>(userdata
)->read(ptr
, size
* nmemb
);
33 return CURL_READFUNC_ABORT
;
37 http_request::null_input_handler::~null_input_handler()
41 uint64_t http_request::null_input_handler::get_length()
46 size_t http_request::null_input_handler::read(char* target
, size_t maxread
)
51 http_request::output_handler::~output_handler()
55 size_t http_request::output_handler::write_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
57 if(reinterpret_cast<http_request::output_handler
*>(userdata
)->canceled
) return 0;
59 reinterpret_cast<http_request::output_handler
*>(userdata
)->write(ptr
, size
* nmemb
);
66 size_t http_request::output_handler::header_fn(void* _ptr
, size_t size
, size_t nmemb
, void* userdata
)
68 size_t hsize
= size
* nmemb
;
69 char* ptr
= (char*)_ptr
;
70 while(hsize
> 0 && (ptr
[hsize
- 1] == '\r' || ptr
[hsize
- 1] == '\n')) hsize
--;
71 char* split
= strchr((char*)ptr
, ':');
72 char* firstns
= split
;
75 while(*firstns
&& (*firstns
== '\t' || *firstns
== ' ')) firstns
++;
77 char* end
= (char*)ptr
+ hsize
;
79 reinterpret_cast<http_request::output_handler
*>(userdata
)->header("", std::string((char*)ptr
, hsize
));
81 reinterpret_cast<http_request::output_handler
*>(userdata
)->header(std::string((char*)ptr
,
82 split
- (char*)ptr
), std::string(firstns
, end
- firstns
));
86 http_request::www_authenticate_extractor::www_authenticate_extractor(
87 std::function
<void(const std::string
& value
)> _callback
)
92 http_request::www_authenticate_extractor::~www_authenticate_extractor()
96 std::string
http_strlower(const std::string
& name
)
98 std::string name2
= name
;
99 for(size_t i
= 0; i
< name2
.length(); i
++)
100 if(name2
[i
] >= 65 && name2
[i
] <= 90) name2
[i
] = name2
[i
] + 32;
104 void http_request::www_authenticate_extractor::header(const std::string
& name
, const std::string
& content
)
106 if(http_strlower(name
) == "www-authenticate") callback(content
);
109 void http_request::www_authenticate_extractor::write(const char* source
, size_t srcsize
)
115 http_request::~http_request()
118 curl_easy_cleanup((CURL
*)handle
);
121 http_request::http_request(const std::string
& verb
, const std::string
& url
)
123 dlnow
= dltotal
= ulnow
= ultotal
= 0;
124 handle
= curl_easy_init();
126 throw std::runtime_error("Can't initialize HTTP transfer");
129 } else if(verb
== "HEAD") {
130 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOBODY
, 1);
131 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
132 } else if(verb
== "POST") {
133 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_POST
, 1);
134 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
136 } else if(verb
== "PUT") {
137 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PUT
, 1);
138 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
141 throw std::runtime_error("Unknown HTTP verb");
142 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_URL
, url
.c_str());
143 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
146 void http_request::do_transfer(input_handler
* inhandler
, output_handler
* outhandler
)
148 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOPROGRESS
, 0);
149 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
150 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEFUNCTION
, http_request::output_handler::write_fn
);
151 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
152 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEDATA
, (void*)outhandler
);
153 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
155 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READFUNCTION
,
156 http_request::input_handler::read_fn
);
157 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
158 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READDATA
, (void*)inhandler
);
159 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
160 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_INFILESIZE_LARGE
,
161 (curl_off_t
)inhandler
->get_length());
162 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
164 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSFUNCTION
, &http_request::progress
);
165 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
166 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSDATA
, (void*)this);
167 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
168 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERFUNCTION
, &http_request::output_handler::header_fn
);
169 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
170 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERDATA
, (void*)outhandler
);
171 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
173 struct curl_slist
* list
= NULL
;
174 if(authorization
!= "") {
175 std::string foo
= "Authorization: " + authorization
;
176 list
= curl_slist_append(list
, foo
.c_str());
179 curl_easy_setopt((CURL
*)handle
, CURLOPT_HTTPHEADER
, list
);
182 err
= curl_easy_perform((CURL
*)handle
);
183 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
186 curl_slist_free_all(list
);
189 void http_request::global_init()
191 curl_global_init(CURL_GLOBAL_ALL
);
194 int http_request::progress(void* userdata
, double dltotal
, double dlnow
, double ultotal
, double ulnow
)
196 return reinterpret_cast<http_request
*>(userdata
)->_progress(dltotal
, dlnow
, ultotal
, ulnow
);
199 int http_request::_progress(double _dltotal
, double _dlnow
, double _ultotal
, double _ulnow
)
208 void http_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
216 long http_request::get_http_code()
219 curl_easy_getinfo((CURL
*)handle
, CURLINFO_RESPONSE_CODE
, &ret
);
223 http_async_request::http_async_request()
233 void http_async_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
237 req
->get_xfer_status(dnow
, dtotal
, unow
, utotal
);
239 dnow
= dtotal
= final_dl
;
240 unow
= utotal
= final_ul
;
246 void async_http_trampoline(http_async_request
* r
)
249 r
->req
->do_transfer(r
->ihandler
, r
->ohandler
);
250 } catch(std::exception
& e
) {
251 threads::alock
h(r
->m
);
252 r
->finished_cond
.notify_all();
256 r
->errormsg
= e
.what();
260 threads::alock
h(r
->m
);
261 r
->http_code
= r
->req
->get_http_code();
262 r
->req
->get_xfer_status(r
->final_dl
, tmp1
, r
->final_ul
, tmp2
);
263 r
->finished_cond
.notify_all();
270 void http_async_request::lauch_async()
275 req
= new http_request(verb
, url
);
276 if(authorization
!= "") req
->set_authorization(authorization
);
278 (new threads::thread(async_http_trampoline
, this))->detach();
279 } catch(std::exception
& e
) {
281 finished_cond
.notify_all();
289 void http_async_request::cancel()
291 if(ihandler
) ihandler
->cancel();
292 if(ohandler
) ohandler
->cancel();
295 property_upload_request::property_upload_request()
301 property_upload_request::~property_upload_request()
305 uint64_t property_upload_request::get_length()
309 std::string X
= (stringfmt() << "," << j
.second
.length() << ":").str();
310 tmp
= tmp
+ X
.length() + j
.first
.length() + j
.second
.length();
315 void property_upload_request::rewind()
321 void property_upload_request::str_helper(const std::string
& str
, char*& target
, size_t& maxread
, size_t& x
,
324 size_t y
= min((uint64_t)maxread
, (uint64_t)(str
.length() - sent
));
330 std::copy(str
.begin() + sent
, str
.begin() + sent
+ y
, target
);
337 void property_upload_request::chr_helper(char ch
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
345 void property_upload_request::len_helper(size_t len
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
347 std::string tmp
= (stringfmt() << len
).str();
348 str_helper(tmp
, target
, maxread
, x
, next
);
351 size_t property_upload_request::read(char* target
, size_t maxread
)
361 if(itr
== data
.end()) {
364 str_helper(itr
->first
, target
, maxread
, x
, 2);
367 chr_helper('=', target
, maxread
, x
, 3);
369 case 3: //Length of value.
370 len_helper(itr
->second
.length(), target
, maxread
, x
, 4);
372 case 4: //The separator of value.
373 chr_helper(':', target
, maxread
, x
, 5);
376 str_helper(itr
->second
, target
, maxread
, x
, 6);
378 case 6: //End of entry.