3 #include "httpauth.hpp"
6 #include "threadtypes.hpp"
7 #include "streamcompress.hpp"
11 #include <boost/iostreams/categories.hpp>
12 #include <boost/iostreams/copy.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/iostreams/stream_buffer.hpp>
15 #include <boost/iostreams/filter/symmetric.hpp>
16 #include <boost/iostreams/filter/zlib.hpp>
17 #include <boost/iostreams/filtering_stream.hpp>
18 #include <boost/iostreams/device/back_inserter.hpp>
20 http_request::input_handler::~input_handler()
24 size_t http_request::input_handler::read_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
26 if(reinterpret_cast<http_request::input_handler
*>(userdata
)->canceled
) return CURL_READFUNC_ABORT
;
28 return reinterpret_cast<http_request::input_handler
*>(userdata
)->read(ptr
, size
* nmemb
);
30 return CURL_READFUNC_ABORT
;
34 http_request::null_input_handler::~null_input_handler()
38 uint64_t http_request::null_input_handler::get_length()
43 size_t http_request::null_input_handler::read(char* target
, size_t maxread
)
48 http_request::output_handler::~output_handler()
52 size_t http_request::output_handler::write_fn(char* ptr
, size_t size
, size_t nmemb
, void* userdata
)
54 if(reinterpret_cast<http_request::output_handler
*>(userdata
)->canceled
) return 0;
56 reinterpret_cast<http_request::output_handler
*>(userdata
)->write(ptr
, size
* nmemb
);
63 size_t http_request::output_handler::header_fn(void* _ptr
, size_t size
, size_t nmemb
, void* userdata
)
65 size_t hsize
= size
* nmemb
;
66 char* ptr
= (char*)_ptr
;
67 while(hsize
> 0 && (ptr
[hsize
- 1] == '\r' || ptr
[hsize
- 1] == '\n')) hsize
--;
68 char* split
= strchr((char*)ptr
, ':');
69 char* firstns
= split
;
72 while(*firstns
&& (*firstns
== '\t' || *firstns
== ' ')) firstns
++;
74 char* end
= (char*)ptr
+ hsize
;
76 reinterpret_cast<http_request::output_handler
*>(userdata
)->header("", std::string((char*)ptr
, hsize
));
78 reinterpret_cast<http_request::output_handler
*>(userdata
)->header(std::string((char*)ptr
,
79 split
- (char*)ptr
), std::string(firstns
, end
- firstns
));
83 http_request::www_authenticate_extractor::www_authenticate_extractor(
84 std::function
<void(const std::string
& value
)> _callback
)
89 http_request::www_authenticate_extractor::~www_authenticate_extractor()
93 std::string
http_strlower(const std::string
& name
)
95 std::string name2
= name
;
96 for(size_t i
= 0; i
< name2
.length(); i
++)
97 if(name2
[i
] >= 65 && name2
[i
] <= 90) name2
[i
] = name2
[i
] + 32;
101 void http_request::www_authenticate_extractor::header(const std::string
& name
, const std::string
& content
)
103 if(http_strlower(name
) == "www-authenticate") callback(content
);
106 void http_request::www_authenticate_extractor::write(const char* source
, size_t srcsize
)
112 http_request::~http_request()
115 curl_easy_cleanup((CURL
*)handle
);
118 http_request::http_request(const std::string
& verb
, const std::string
& url
)
120 dlnow
= dltotal
= ulnow
= ultotal
= 0;
121 handle
= curl_easy_init();
123 throw std::runtime_error("Can't initialize HTTP transfer");
126 } else if(verb
== "HEAD") {
127 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOBODY
, 1);
128 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
129 } else if(verb
== "POST") {
130 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_POST
, 1);
131 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
133 } else if(verb
== "PUT") {
134 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PUT
, 1);
135 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
138 throw std::runtime_error("Unknown HTTP verb");
139 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_URL
, url
.c_str());
140 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
143 void http_request::do_transfer(input_handler
* inhandler
, output_handler
* outhandler
)
145 auto err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_NOPROGRESS
, 0);
146 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
147 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEFUNCTION
, http_request::output_handler::write_fn
);
148 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
149 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_WRITEDATA
, (void*)outhandler
);
150 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
152 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READFUNCTION
,
153 http_request::input_handler::read_fn
);
154 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
155 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_READDATA
, (void*)inhandler
);
156 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
157 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_INFILESIZE_LARGE
,
158 (curl_off_t
)inhandler
->get_length());
159 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
161 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSFUNCTION
, &http_request::progress
);
162 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
163 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_PROGRESSDATA
, (void*)this);
164 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
165 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERFUNCTION
, &http_request::output_handler::header_fn
);
166 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
167 err
= curl_easy_setopt((CURL
*)handle
, CURLOPT_HEADERDATA
, (void*)outhandler
);
168 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
170 struct curl_slist
* list
= NULL
;
171 if(authorization
!= "") {
172 std::string foo
= "Authorization: " + authorization
;
173 list
= curl_slist_append(list
, foo
.c_str());
176 curl_easy_setopt((CURL
*)handle
, CURLOPT_HTTPHEADER
, list
);
179 err
= curl_easy_perform((CURL
*)handle
);
180 if(err
) throw std::runtime_error(curl_easy_strerror(err
));
183 curl_slist_free_all(list
);
186 void http_request::global_init()
188 curl_global_init(CURL_GLOBAL_ALL
);
191 int http_request::progress(void* userdata
, double dltotal
, double dlnow
, double ultotal
, double ulnow
)
193 return reinterpret_cast<http_request
*>(userdata
)->_progress(dltotal
, dlnow
, ultotal
, ulnow
);
196 int http_request::_progress(double _dltotal
, double _dlnow
, double _ultotal
, double _ulnow
)
204 void http_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
212 long http_request::get_http_code()
215 curl_easy_getinfo((CURL
*)handle
, CURLINFO_RESPONSE_CODE
, &ret
);
219 http_async_request::http_async_request()
229 void http_async_request::get_xfer_status(int64_t& dnow
, int64_t& dtotal
, int64_t& unow
, int64_t& utotal
)
233 req
->get_xfer_status(dnow
, dtotal
, unow
, utotal
);
235 dnow
= dtotal
= final_dl
;
236 unow
= utotal
= final_ul
;
242 void async_http_trampoline(http_async_request
* r
)
245 r
->req
->do_transfer(r
->ihandler
, r
->ohandler
);
246 } catch(std::exception
& e
) {
247 umutex_class
h(r
->m
);
248 r
->finished_cond
.notify_all();
252 r
->errormsg
= e
.what();
256 umutex_class
h(r
->m
);
257 r
->http_code
= r
->req
->get_http_code();
258 r
->req
->get_xfer_status(r
->final_dl
, tmp1
, r
->final_ul
, tmp2
);
259 r
->finished_cond
.notify_all();
266 void http_async_request::lauch_async()
271 req
= new http_request(verb
, url
);
272 if(authorization
!= "") req
->set_authorization(authorization
);
274 (new thread_class(async_http_trampoline
, this))->detach();
275 } catch(std::exception
& e
) {
277 finished_cond
.notify_all();
285 void http_async_request::cancel()
287 if(ihandler
) ihandler
->cancel();
288 if(ohandler
) ohandler
->cancel();
291 property_upload_request::property_upload_request()
297 property_upload_request::~property_upload_request()
301 uint64_t property_upload_request::get_length()
305 std::string X
= (stringfmt() << "," << j
.second
.length() << ":").str();
306 tmp
= tmp
+ X
.length() + j
.first
.length() + j
.second
.length();
311 void property_upload_request::rewind()
317 void property_upload_request::str_helper(const std::string
& str
, char*& target
, size_t& maxread
, size_t& x
,
320 size_t y
= min((uint64_t)maxread
, (uint64_t)(str
.length() - sent
));
326 std::copy(str
.begin() + sent
, str
.begin() + sent
+ y
, target
);
333 void property_upload_request::chr_helper(char ch
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
341 void property_upload_request::len_helper(size_t len
, char*& target
, size_t& maxread
, size_t& x
, unsigned next
)
343 std::string tmp
= (stringfmt() << len
).str();
344 str_helper(tmp
, target
, maxread
, x
, next
);
347 size_t property_upload_request::read(char* target
, size_t maxread
)
358 if(itr
== data
.end()) {
361 str_helper(itr
->first
, target
, maxread
, x
, 2);
364 chr_helper('=', target
, maxread
, x
, 3);
366 case 3: //Length of value.
367 len_helper(itr
->second
.length(), target
, maxread
, x
, 4);
369 case 4: //The separator of value.
370 chr_helper(':', target
, maxread
, x
, 5);
373 str_helper(itr
->second
, target
, maxread
, x
, 6);
375 case 6: //End of entry.