about summary refs log tree commit diff stats
path: root/src/request.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 11:14:39 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-08-05 11:14:39 -0400
commit38203b745ae1903ba0804ed5532b78d255bea635 (patch)
tree52f57ce85e65361c534c461abc82fb1ed9768d49 /src/request.cpp
parent7c44fd17bb6be54a2ea4b60761e91053ca988977 (diff)
downloadlibtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.gz
libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.tar.bz2
libtwittercpp-38203b745ae1903ba0804ed5532b78d255bea635.zip
Added timeline polling
Because the streaming API will sunset on August 16th, it is essential to implement timeline polling so that the library can still be used to access tweets. This commit breaks the current API even for clients still using the streaming API because the OAuth connection data was pulled from twitter::client into twitter::auth. Other than that, almost everything works the same, and if a client wants to update their libtwitter++ within the next week and a half, they are free to.
Diffstat (limited to 'src/request.cpp')
-rw-r--r--src/request.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/request.cpp b/src/request.cpp new file mode 100644 index 0000000..a79c7f0 --- /dev/null +++ b/src/request.cpp
@@ -0,0 +1,264 @@
1#include "request.h"
2#include <json.hpp>
3#include "codes.h"
4
5// These are here for debugging curl stuff
6
7static
8void dump(const char *text,
9 FILE *stream, unsigned char *ptr, size_t size)
10{
11 size_t i;
12 size_t c;
13 unsigned int width=80;
14
15 fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n",
16 text, (long)size, (long)size);
17
18 for(i=0; i<size; i+= width) {
19 fprintf(stream, "%4.4lx: ", (long)i);
20
21 /* show hex to the left
22 for(c = 0; c < width; c++) {
23 if(i+c < size)
24 fprintf(stream, "%02x ", ptr[i+c]);
25 else
26 fputs(" ", stream);
27 }*/
28
29 /* show data on the right */
30 for(c = 0; (c < width) && (i+c < size); c++) {
31 char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.';
32 fputc(x, stream);
33 }
34
35 fputc('\n', stream); /* newline */
36 }
37}
38
39static
40int my_trace(CURL *handle, curl_infotype type,
41 char *data, size_t size,
42 void *userp)
43{
44 const char *text;
45 (void)handle; /* prevent compiler warning */
46
47 switch (type) {
48 case CURLINFO_TEXT:
49 fprintf(stderr, "== Info: %s", data);
50 default: /* in case a new one is introduced to shock us */
51 return 0;
52
53 case CURLINFO_HEADER_OUT:
54 text = "=> Send header";
55 break;
56 case CURLINFO_DATA_OUT:
57 text = "=> Send data";
58 break;
59 case CURLINFO_SSL_DATA_OUT:
60 text = "=> Send SSL data";
61 break;
62 case CURLINFO_HEADER_IN:
63 text = "<= Recv header";
64 break;
65 case CURLINFO_DATA_IN:
66 text = "<= Recv data";
67 break;
68 case CURLINFO_SSL_DATA_IN:
69 text = "<= Recv SSL data";
70 break;
71 }
72
73 dump(text, stderr, (unsigned char *)data, size);
74 return 0;
75}
76
77namespace twitter {
78
79 request::request(
80 std::string url) try :
81 ios_(output_),
82 conn_(ios_)
83 {
84 conn_.add<CURLOPT_URL>(url.c_str());
85 } catch (const curl::curl_easy_exception& error)
86 {
87 std::throw_with_nested(connection_error());
88 }
89
90 std::string request::perform()
91 {
92 try
93 {
94 conn_.perform();
95 } catch (const curl::curl_easy_exception& error)
96 {
97 std::throw_with_nested(connection_error());
98 }
99
100 int response_code = conn_.get_info<CURLINFO_RESPONSE_CODE>().get();
101 std::string result = output_.str();
102
103 if (response_code / 100 != 2)
104 {
105 nlohmann::json response_json;
106
107 try
108 {
109 response_json = nlohmann::json::parse(result);
110 } catch (const std::invalid_argument& e)
111 {
112 std::throw_with_nested(invalid_response(result));
113 }
114
115 for (nlohmann::json& error : response_json["errors"])
116 {
117 int error_code;
118 std::string error_message;
119
120 try
121 {
122 error_code = error["code"].get<int>();
123 error_message = error["message"].get<std::string>();
124 } catch (const std::domain_error& e)
125 {
126 std::throw_with_nested(invalid_response(result));
127 }
128
129 switch (error_code)
130 {
131 case 32:
132 case 135:
133 case 215:
134 throw bad_auth(error_message);
135
136 case 44:
137 throw invalid_media(error_message);
138
139 case 64:
140 throw account_suspended(error_message);
141
142 case 88:
143 throw rate_limit_exceeded(error_message);
144
145 case 89:
146 throw bad_token(error_message);
147
148 case 130:
149 throw server_overloaded(error_message);
150
151 case 131:
152 throw server_error(error_message);
153
154 case 185:
155 throw update_limit_exceeded(error_message);
156
157 case 186:
158 throw bad_length(error_message);
159
160 case 187:
161 throw duplicate_status(error_message);
162
163 case 226:
164 throw suspected_spam(error_message);
165
166 case 261:
167 throw write_restricted(error_message);
168 }
169 }
170
171 if (response_code == 429)
172 {
173 throw rate_limit_exceeded("HTTP 429 Too Many Requests");
174 } else if (response_code == 500)
175 {
176 throw server_error("HTTP 500 Internal Server Error");
177 } else if (response_code == 502)
178 {
179 throw server_unavailable("HTTP 502 Bad Gateway");
180 } else if (response_code == 503)
181 {
182 throw server_overloaded("HTTP 503 Service Unavailable");
183 } else if (response_code == 504)
184 {
185 throw server_timeout("HTTP 504 Gateway Timeout");
186 }
187
188 throw unknown_error(response_code, result);
189 }
190
191 return result;
192 }
193
194 get::get(
195 const auth& tauth,
196 std::string url) try :
197 request(url)
198 {
199 std::string oauthHeader =
200 tauth.getClient().getFormattedHttpHeader(OAuth::Http::Get, url, "");
201
202 if (!oauthHeader.empty())
203 {
204 headers_.add(std::move(oauthHeader));
205 }
206
207 conn_.add<CURLOPT_HTTPHEADER>(headers_.get());
208 } catch (const OAuth::ParseError& error)
209 {
210 std::throw_with_nested(connection_error());
211 } catch (const curl::curl_easy_exception& error)
212 {
213 std::throw_with_nested(connection_error());
214 }
215
216 post::post(
217 const auth& tauth,
218 std::string url,
219 std::string datastr) try :
220 request(url)
221 {
222 std::string oauthHeader =
223 tauth.getClient().getFormattedHttpHeader(OAuth::Http::Post, url, datastr);
224
225 if (!oauthHeader.empty())
226 {
227 headers_.add(std::move(oauthHeader));
228 }
229
230 conn_.add<CURLOPT_HTTPHEADER>(headers_.get());
231 conn_.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str());
232 } catch (const OAuth::ParseError& error)
233 {
234 std::throw_with_nested(connection_error());
235 } catch (const curl::curl_easy_exception& error)
236 {
237 std::throw_with_nested(connection_error());
238 }
239
240 multipost::multipost(
241 const auth& tauth,
242 std::string url,
243 const curl_httppost* fields) try :
244 request(url)
245 {
246 std::string oauthHeader =
247 tauth.getClient().getFormattedHttpHeader(OAuth::Http::Post, url, "");
248
249 if (!oauthHeader.empty())
250 {
251 headers_.add(std::move(oauthHeader));
252 }
253
254 conn_.add<CURLOPT_HTTPHEADER>(headers_.get());
255 conn_.add<CURLOPT_HTTPPOST>(fields);
256 } catch (const OAuth::ParseError& error)
257 {
258 std::throw_with_nested(connection_error());
259 } catch (const curl::curl_easy_exception& error)
260 {
261 std::throw_with_nested(connection_error());
262 }
263
264}