about summary refs log tree commit diff stats
path: root/src/request.cpp
diff options
context:
space:
mode:
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}