6 #include "httpauth.hpp"
10 #include "streamcompress.hpp"
11 #include <curl/curl.h>
15 #include <boost/iostreams/categories.hpp>
16 #include <boost/iostreams/copy.hpp>
17 #include <boost/iostreams/stream.hpp>
18 #include <boost/iostreams/stream_buffer.hpp>
19 #include <boost/iostreams/filter/symmetric.hpp>
20 #include <boost/iostreams/filter/zlib.hpp>
21 #include <boost/iostreams/filtering_stream.hpp>
22 #include <boost/iostreams/device/back_inserter.hpp>
24 http_request::input_handler::~input_handler()
28 size_t http_request::input_handler::read_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
30 if(reinterpret_cast<http_request::input_handler
*>(userdata
)->canceled
) return CURL_READFUNC_ABORT
;
32 return reinterpret_cast<http_request::input_handler
*>(userdata
)->read(ptr
, size
* nmemb
);
34 return CURL_READFUNC_ABORT
;
38 http_request::null_input_handler::~null_input_handler()
42 uint64_t http_request::null_input_handler::get_length()
47 size_t http_request::null_input_handler::read(char* target
, size_t maxread
)
52 http_request::output_handler::~output_handler()
56 size_t http_request::output_handler::write_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
58 if(reinterpret_cast<http_request::output_handler
*>(userdata
)->canceled
) return 0;
60 reinterpret_cast<http_request::output_handler
*>(userdata
)->write(ptr
, size
* nmemb
);
67 size_t http_request::output_handler::header_fn(void* _ptr
, size_t size
, size_t nmemb
, void* userdata
)
69 size_t hsize
= size
* nmemb
;
70 char* ptr
= (char*)_ptr
;
71 while(hsize
> 0 && (ptr
[hsize
- 1] == '\r' || ptr
[hsize
- 1] == '\n')) hsize
--;
72 char* split
= strchr((char*)ptr
, ':');
73 char* firstns
= split
;
76 while(*firstns
&& (*firstns
== '\t' || *firstns
== ' ')) firstns
++;
78 char* end
= (char*)ptr
+ hsize
;
80 reinterpret_cast<http_request::output_handler
*>(userdata
)->header("", std::string((char*)ptr
, hsize
));
82 reinterpret_cast<http_request::output_handler
*>(userdata
)->header(std::string((char*)ptr
,
83 split
- (char*)ptr
), std::string(firstns
, end
- firstns
));
87 http_request::www_authenticate_extractor::www_authenticate_extractor(
88 std::function
<void(const std::string
& value
)> _callback
)
93 http_request::www_authenticate_extractor::~www_authenticate_extractor()
97 std::string
http_strlower(const std::string
& name
)
99 std::string name2
= name
;
100 for(size_t i
= 0; i
< name2
.length(); i
++)
101 if(name2
[i
] >= 65 && name2
[i
] <= 90) name2
[i
] = name2
[i
] + 32;
105 void http_request::www_authenticate_extractor::header(const std::string
& name
, const std::string
& content
)
107 if(http_strlower(name
) == "www-authenticate") callback(content
);
110 void http_request::www_authenticate_extractor::write(const char* source
, size_t srcsize
)
116 http_request::~http_request()
119 curl_easy_cleanup((CURL
*)handle
);
122 http_request::http_request(const std::string
& verb
, const std::string
& url
)
124 dlnow
= dltotal
= ulnow
= ultotal
= 0;
125 handle
= curl_easy_init();
127 throw std::runtime_error("Can't initialize HTTP transfer");
130 } else if(verb
== "HEAD") {
131 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOBODY
, 1);
132 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
133 } else if(verb
== "POST") {
134 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_POST
, 1);
135 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
137 } else if(verb
== "PUT") {
138 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PUT
, 1);
139 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
142 throw std::runtime_error("Unknown HTTP verb");
143 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_URL
, url
.c_str());
144 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
147 void http_request::do_transfer(input_handler
* inhandler
, output_handler
* outhandler
)
149 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOPROGRESS
, 0);
150 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
151 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEFUNCTION
, http_request::output_handler::write_fn
);
152 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
153 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEDATA
, (void*)outhandler
);
154 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
156 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READFUNCTION
,
157 http_request::input_handler::read_fn
);
158 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
159 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READDATA
, (void*)inhandler
);
160 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
161 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_INFILESIZE_LARGE
,
162 (curl_off_t
)inhandler
->get_length());
163 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
165 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSFUNCTION
, &http_request::progress
);
166 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
167 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSDATA
, (void*)this);
168 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
169 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERFUNCTION
, &http_request::output_handler::header_fn
);
170 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
171 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERDATA
, (void*)outhandler
);
172 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
174 struct curl_slist
* list
= NULL
;
175 if(authorization
!= "") {
176 std::string foo
= "Authorization: " + authorization
;
177 list
= curl_slist_append(list
, foo
.c_str());
180 curl_easy_setopt((CURL
*)handle
, CURLOPT_HTTPHEADER
, list
);
183 err
= curl_easy_perform((CURL
*)handle
);
184 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
187 curl_slist_free_all(list
);
190 void http_request::global_init()
192 curl_global_init(CURL_GLOBAL_ALL
);
195 int http_request::progress(void* userdata
, double dltotal
, double dlnow
, double ultotal
, double ulnow
)
197 return reinterpret_cast<http_request
*>(userdata
)->_progress(dltotal
, dlnow
, ultotal
, ulnow
);
200 int http_request::_progress(double _dltotal
, double _dlnow
, double _ultotal
, double _ulnow
)
209 void http_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
217 uint32_t http_request::get_http_code()
220 curl_easy_getinfo((CURL
*)handle
, CURLINFO_RESPONSE_CODE
, &ret
);
224 http_async_request::http_async_request()
234 void http_async_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
238 req
->get_xfer_status(dnow
, dtotal
, unow
, utotal
);
240 dnow
= dtotal
= final_dl
;
241 unow
= utotal
= final_ul
;
247 void async_http_trampoline(http_async_request
* r
)
250 r
->req
->do_transfer(r
->ihandler
, r
->ohandler
);
251 } catch(std::exception
& e
) {
252 threads::alock
h(r
->m
);
253 r
->finished_cond
.notify_all();
257 r
->errormsg
= e
.what();
261 threads::alock
h(r
->m
);
262 r
->http_code
= r
->req
->get_http_code();
263 r
->req
->get_xfer_status(r
->final_dl
, tmp1
, r
->final_ul
, tmp2
);
264 r
->finished_cond
.notify_all();
271 void http_async_request::lauch_async()
276 req
= new http_request(verb
, url
);
277 if(authorization
!= "") req
->set_authorization(authorization
);
279 (new threads::thread(async_http_trampoline
, this))->detach();
280 } catch(std::exception
& e
) {
282 finished_cond
.notify_all();
290 void http_async_request::cancel()
292 if(ihandler
) ihandler
->cancel();
293 if(ohandler
) ohandler
->cancel();
296 property_upload_request::property_upload_request()
302 property_upload_request::~property_upload_request()
306 uint64_t property_upload_request::get_length()
310 std::string X
= (stringfmt() << "," << j
.second
.length() << ":").str();
311 tmp
= tmp
+ X
.length() + j
.first
.length() + j
.second
.length();
316 void property_upload_request::rewind()
322 void property_upload_request::str_helper(const std::string
& str
, char*& target
, size_t& maxread
, size_t& x
,
325 size_t y
= min((uint64_t)maxread
, (uint64_t)(str
.length() - sent
));
331 std::copy(str
.begin() + sent
, str
.begin() + sent
+ y
, target
);
338 void property_upload_request::chr_helper(char ch
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
346 void property_upload_request::len_helper(size_t len
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
348 std::string tmp
= (stringfmt() << len
).str();
349 str_helper(tmp
, target
, maxread
, x
, next
);
352 size_t property_upload_request::read(char* target
, size_t maxread
)
362 if(itr
== data
.end()) {
365 str_helper(itr
->first
, target
, maxread
, x
, 2);
368 chr_helper('=', target
, maxread
, x
, 3);
370 case 3: //Length of value.
371 len_helper(itr
->second
.length(), target
, maxread
, x
, 4);
373 case 4: //The separator of value.
374 chr_helper(':', target
, maxread
, x
, 5);
377 str_helper(itr
->second
, target
, maxread
, x
, 6);
379 case 6: //End of entry.