4 #include "httpauth.hpp"
7 #include "threadtypes.hpp"
8 #include "streamcompress.hpp"
12 #include <boost/iostreams/categories.hpp>
13 #include <boost/iostreams/copy.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/iostreams/stream_buffer.hpp>
16 #include <boost/iostreams/filter/symmetric.hpp>
17 #include <boost/iostreams/filter/zlib.hpp>
18 #include <boost/iostreams/filtering_stream.hpp>
19 #include <boost/iostreams/device/back_inserter.hpp>
21 http_request::input_handler::~input_handler()
25 size_t http_request::input_handler::read_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
27 if(reinterpret_cast<http_request::input_handler
*>(userdata
)->canceled
) return CURL_READFUNC_ABORT
;
29 return reinterpret_cast<http_request::input_handler
*>(userdata
)->read(ptr
, size
* nmemb
);
31 return CURL_READFUNC_ABORT
;
35 http_request::null_input_handler::~null_input_handler()
39 uint64_t http_request::null_input_handler::get_length()
44 size_t http_request::null_input_handler::read(char* target
, size_t maxread
)
49 http_request::output_handler::~output_handler()
53 size_t http_request::output_handler::write_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
55 if(reinterpret_cast<http_request::output_handler
*>(userdata
)->canceled
) return 0;
57 reinterpret_cast<http_request::output_handler
*>(userdata
)->write(ptr
, size
* nmemb
);
64 size_t http_request::output_handler::header_fn(void* _ptr
, size_t size
, size_t nmemb
, void* userdata
)
66 size_t hsize
= size
* nmemb
;
67 char* ptr
= (char*)_ptr
;
68 while(hsize
> 0 && (ptr
[hsize
- 1] == '\r' || ptr
[hsize
- 1] == '\n')) hsize
--;
69 char* split
= strchr((char*)ptr
, ':');
70 char* firstns
= split
;
73 while(*firstns
&& (*firstns
== '\t' || *firstns
== ' ')) firstns
++;
75 char* end
= (char*)ptr
+ hsize
;
77 reinterpret_cast<http_request::output_handler
*>(userdata
)->header("", std::string((char*)ptr
, hsize
));
79 reinterpret_cast<http_request::output_handler
*>(userdata
)->header(std::string((char*)ptr
,
80 split
- (char*)ptr
), std::string(firstns
, end
- firstns
));
84 http_request::www_authenticate_extractor::www_authenticate_extractor(
85 std::function
<void(const std::string
& value
)> _callback
)
90 http_request::www_authenticate_extractor::~www_authenticate_extractor()
94 std::string
http_strlower(const std::string
& name
)
96 std::string name2
= name
;
97 for(size_t i
= 0; i
< name2
.length(); i
++)
98 if(name2
[i
] >= 65 && name2
[i
] <= 90) name2
[i
] = name2
[i
] + 32;
102 void http_request::www_authenticate_extractor::header(const std::string
& name
, const std::string
& content
)
104 if(http_strlower(name
) == "www-authenticate") callback(content
);
107 void http_request::www_authenticate_extractor::write(const char* source
, size_t srcsize
)
113 http_request::~http_request()
116 curl_easy_cleanup((CURL
*)handle
);
119 http_request::http_request(const std::string
& verb
, const std::string
& url
)
121 dlnow
= dltotal
= ulnow
= ultotal
= 0;
122 handle
= curl_easy_init();
124 throw std::runtime_error("Can't initialize HTTP transfer");
127 } else if(verb
== "HEAD") {
128 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOBODY
, 1);
129 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
130 } else if(verb
== "POST") {
131 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_POST
, 1);
132 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
134 } else if(verb
== "PUT") {
135 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PUT
, 1);
136 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
139 throw std::runtime_error("Unknown HTTP verb");
140 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_URL
, url
.c_str());
141 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
144 void http_request::do_transfer(input_handler
* inhandler
, output_handler
* outhandler
)
146 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOPROGRESS
, 0);
147 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
148 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEFUNCTION
, http_request::output_handler::write_fn
);
149 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
150 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEDATA
, (void*)outhandler
);
151 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
153 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READFUNCTION
,
154 http_request::input_handler::read_fn
);
155 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
156 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READDATA
, (void*)inhandler
);
157 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
158 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_INFILESIZE_LARGE
,
159 (curl_off_t
)inhandler
->get_length());
160 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
162 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSFUNCTION
, &http_request::progress
);
163 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
164 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSDATA
, (void*)this);
165 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
166 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERFUNCTION
, &http_request::output_handler::header_fn
);
167 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
168 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERDATA
, (void*)outhandler
);
169 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
171 struct curl_slist
* list
= NULL
;
172 if(authorization
!= "") {
173 std::string foo
= "Authorization: " + authorization
;
174 list
= curl_slist_append(list
, foo
.c_str());
177 curl_easy_setopt((CURL
*)handle
, CURLOPT_HTTPHEADER
, list
);
180 err
= curl_easy_perform((CURL
*)handle
);
181 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
184 curl_slist_free_all(list
);
187 void http_request::global_init()
189 curl_global_init(CURL_GLOBAL_ALL
);
192 int http_request::progress(void* userdata
, double dltotal
, double dlnow
, double ultotal
, double ulnow
)
194 return reinterpret_cast<http_request
*>(userdata
)->_progress(dltotal
, dlnow
, ultotal
, ulnow
);
197 int http_request::_progress(double _dltotal
, double _dlnow
, double _ultotal
, double _ulnow
)
206 void http_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
214 long http_request::get_http_code()
217 curl_easy_getinfo((CURL
*)handle
, CURLINFO_RESPONSE_CODE
, &ret
);
221 http_async_request::http_async_request()
231 void http_async_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
235 req
->get_xfer_status(dnow
, dtotal
, unow
, utotal
);
237 dnow
= dtotal
= final_dl
;
238 unow
= utotal
= final_ul
;
244 void async_http_trampoline(http_async_request
* r
)
247 r
->req
->do_transfer(r
->ihandler
, r
->ohandler
);
248 } catch(std::exception
& e
) {
249 umutex_class
h(r
->m
);
250 r
->finished_cond
.notify_all();
254 r
->errormsg
= e
.what();
258 umutex_class
h(r
->m
);
259 r
->http_code
= r
->req
->get_http_code();
260 r
->req
->get_xfer_status(r
->final_dl
, tmp1
, r
->final_ul
, tmp2
);
261 r
->finished_cond
.notify_all();
268 void http_async_request::lauch_async()
273 req
= new http_request(verb
, url
);
274 if(authorization
!= "") req
->set_authorization(authorization
);
276 (new thread_class(async_http_trampoline
, this))->detach();
277 } catch(std::exception
& e
) {
279 finished_cond
.notify_all();
287 void http_async_request::cancel()
289 if(ihandler
) ihandler
->cancel();
290 if(ohandler
) ohandler
->cancel();
293 property_upload_request::property_upload_request()
299 property_upload_request::~property_upload_request()
303 uint64_t property_upload_request::get_length()
307 std::string X
= (stringfmt() << "," << j
.second
.length() << ":").str();
308 tmp
= tmp
+ X
.length() + j
.first
.length() + j
.second
.length();
313 void property_upload_request::rewind()
319 void property_upload_request::str_helper(const std::string
& str
, char*& target
, size_t& maxread
, size_t& x
,
322 size_t y
= min((uint64_t)maxread
, (uint64_t)(str
.length() - sent
));
328 std::copy(str
.begin() + sent
, str
.begin() + sent
+ y
, target
);
335 void property_upload_request::chr_helper(char ch
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
343 void property_upload_request::len_helper(size_t len
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
345 std::string tmp
= (stringfmt() << len
).str();
346 str_helper(tmp
, target
, maxread
, x
, next
);
349 size_t property_upload_request::read(char* target
, size_t maxread
)
360 if(itr
== data
.end()) {
363 str_helper(itr
->first
, target
, maxread
, x
, 2);
366 chr_helper('=', target
, maxread
, x
, 3);
368 case 3: //Length of value.
369 len_helper(itr
->second
.length(), target
, maxread
, x
, 4);
371 case 4: //The separator of value.
372 chr_helper(':', target
, maxread
, x
, 5);
375 str_helper(itr
->second
, target
, maxread
, x
, 6);
377 case 6: //End of entry.