SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
SWGHttpRequest.cpp
Go to the documentation of this file.
1 
13 #include "SWGHttpRequest.h"
14 #include <QDateTime>
15 #include <QUrl>
16 #include <QFileInfo>
17 #include <QBuffer>
18 #include <QtGlobal>
19 
20 
21 namespace SWGSDRangel {
22 
24  initialize();
25 }
26 
27 SWGHttpRequestInput::SWGHttpRequestInput(QString v_url_str, QString v_http_method) {
28  initialize();
29  url_str = v_url_str;
30  http_method = v_http_method;
31 }
32 
35  url_str = "";
36  http_method = "GET";
37 }
38 
39 void SWGHttpRequestInput::add_var(QString key, QString value) {
40  vars[key] = value;
41 }
42 
43 void SWGHttpRequestInput::add_file(QString variable_name, QString local_filename, QString request_filename, QString mime_type) {
45  file.variable_name = variable_name;
46  file.local_filename = local_filename;
47  file.request_filename = request_filename;
48  file.mime_type = mime_type;
49  files.append(file);
50 }
51 
52 
54  : QObject(parent), manager(nullptr)
55 {
56  qsrand(QDateTime::currentDateTime().toTime_t());
57 
58  manager = new QNetworkAccessManager(this);
59  connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_manager_finished(QNetworkReply*)));
60 }
61 
63 }
64 
65 QString SWGHttpRequestWorker::http_attribute_encode(QString attribute_name, QString input) {
66  // result structure follows RFC 5987
67  bool need_utf_encoding = false;
68  QString result = "";
69  QByteArray input_c = input.toLocal8Bit();
70  char c;
71  for (int i = 0; i < input_c.length(); i++) {
72  c = input_c.at(i);
73  if (c == '\\' || c == '/' || c == '\0' || c < ' ' || c > '~') {
74  // ignore and request utf-8 version
75  need_utf_encoding = true;
76  }
77  else if (c == '"') {
78  result += "\\\"";
79  }
80  else {
81  result += c;
82  }
83  }
84 
85  if (result.length() == 0) {
86  need_utf_encoding = true;
87  }
88 
89  if (!need_utf_encoding) {
90  // return simple version
91  return QString("%1=\"%2\"").arg(attribute_name, result);
92  }
93 
94  QString result_utf8 = "";
95  for (int i = 0; i < input_c.length(); i++) {
96  c = input_c.at(i);
97  if (
98  (c >= '0' && c <= '9')
99  || (c >= 'A' && c <= 'Z')
100  || (c >= 'a' && c <= 'z')
101  ) {
102  result_utf8 += c;
103  }
104  else {
105  result_utf8 += "%" + QString::number(static_cast<unsigned char>(input_c.at(i)), 16).toUpper();
106  }
107  }
108 
109  // return enhanced version with UTF-8 support
110  return QString("%1=\"%2\"; %1*=utf-8''%3").arg(attribute_name, result, result_utf8);
111 }
112 
114 
115  // reset variables
116 
117  QByteArray request_content = "";
118  response = "";
119  error_type = QNetworkReply::NoError;
120  error_str = "";
121  bool isFormData = false;
122 
123 
124  // decide on the variable layout
125 
126  if (input->files.length() > 0) {
127  input->var_layout = MULTIPART;
128  }
129  if (input->var_layout == NOT_SET) {
130  input->var_layout = input->http_method == "GET" || input->http_method == "HEAD" ? ADDRESS : URL_ENCODED;
131  }
132 
133 
134  // prepare request content
135 
136  QString boundary = "";
137 
138  if (input->var_layout == ADDRESS || input->var_layout == URL_ENCODED) {
139  // variable layout is ADDRESS or URL_ENCODED
140 
141  if (input->vars.count() > 0) {
142  bool first = true;
143  isFormData = true;
144  foreach (QString key, input->vars.keys()) {
145  if (!first) {
146  request_content.append("&");
147  }
148  first = false;
149 
150  request_content.append(QUrl::toPercentEncoding(key));
151  request_content.append("=");
152  request_content.append(QUrl::toPercentEncoding(input->vars.value(key)));
153  }
154 
155  if (input->var_layout == ADDRESS) {
156  input->url_str += "?" + request_content;
157  request_content = "";
158  }
159  }
160  }
161  else {
162  // variable layout is MULTIPART
163 
164  boundary = "__-----------------------"
165  + QString::number(QDateTime::currentDateTime().toTime_t())
166  + QString::number(qrand());
167  QString boundary_delimiter = "--";
168  QString new_line = "\r\n";
169 
170  // add variables
171  foreach (QString key, input->vars.keys()) {
172  // add boundary
173  request_content.append(boundary_delimiter);
174  request_content.append(boundary);
175  request_content.append(new_line);
176 
177  // add header
178  request_content.append("Content-Disposition: form-data; ");
179  request_content.append(http_attribute_encode("name", key));
180  request_content.append(new_line);
181  request_content.append("Content-Type: text/plain");
182  request_content.append(new_line);
183 
184  // add header to body splitter
185  request_content.append(new_line);
186 
187  // add variable content
188  request_content.append(input->vars.value(key));
189  request_content.append(new_line);
190  }
191 
192  // add files
193  for (QList<SWGHttpRequestInputFileElement>::iterator file_info = input->files.begin(); file_info != input->files.end(); file_info++) {
194  QFileInfo fi(file_info->local_filename);
195 
196  // ensure necessary variables are available
197  if (
198  file_info->local_filename == nullptr || file_info->local_filename.isEmpty()
199  || file_info->variable_name == nullptr || file_info->variable_name.isEmpty()
200  || !fi.exists() || !fi.isFile() || !fi.isReadable()
201  ) {
202  // silent abort for the current file
203  continue;
204  }
205 
206  QFile file(file_info->local_filename);
207  if (!file.open(QIODevice::ReadOnly)) {
208  // silent abort for the current file
209  continue;
210  }
211 
212  // ensure filename for the request
213  if (file_info->request_filename == nullptr || file_info->request_filename.isEmpty()) {
214  file_info->request_filename = fi.fileName();
215  if (file_info->request_filename.isEmpty()) {
216  file_info->request_filename = "file";
217  }
218  }
219 
220  // add boundary
221  request_content.append(boundary_delimiter);
222  request_content.append(boundary);
223  request_content.append(new_line);
224 
225  // add header
226  request_content.append(QString("Content-Disposition: form-data; %1; %2").arg(
227  http_attribute_encode("name", file_info->variable_name),
228  http_attribute_encode("filename", file_info->request_filename)
229  ));
230  request_content.append(new_line);
231 
232  if (file_info->mime_type != nullptr && !file_info->mime_type.isEmpty()) {
233  request_content.append("Content-Type: ");
234  request_content.append(file_info->mime_type);
235  request_content.append(new_line);
236  }
237 
238  request_content.append("Content-Transfer-Encoding: binary");
239  request_content.append(new_line);
240 
241  // add header to body splitter
242  request_content.append(new_line);
243 
244  // add file content
245  request_content.append(file.readAll());
246  request_content.append(new_line);
247 
248  file.close();
249  }
250 
251  // add end of body
252  request_content.append(boundary_delimiter);
253  request_content.append(boundary);
254  request_content.append(boundary_delimiter);
255  }
256 
257  if(input->request_body.size() > 0) {
258  qDebug() << "got a request body";
259  request_content.clear();
260  request_content.append(input->request_body);
261  }
262  // prepare connection
263 
264  QNetworkRequest request = QNetworkRequest(QUrl(input->url_str));
266  request.setSslConfiguration(*SWGHttpRequestWorker::sslDefaultConfiguration);
267  }
268  request.setRawHeader("User-Agent", "Swagger-Client");
269  foreach(QString key, input->headers.keys()) {
270  request.setRawHeader(key.toStdString().c_str(), input->headers.value(key).toStdString().c_str());
271  }
272 
273  if (request_content.size() > 0 && !isFormData) {
274  request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
275  }
276  else if (input->var_layout == URL_ENCODED) {
277  request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
278  }
279  else if (input->var_layout == MULTIPART) {
280  request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
281  }
282 
283  if (input->http_method == "GET") {
284  manager->get(request);
285  }
286  else if (input->http_method == "POST") {
287  manager->post(request, request_content);
288  }
289  else if (input->http_method == "PUT") {
290  manager->put(request, request_content);
291  }
292  else if (input->http_method == "HEAD") {
293  manager->head(request);
294  }
295  else if (input->http_method == "DELETE") {
296  manager->deleteResource(request);
297  }
298  else {
299 #if (QT_VERSION >= 0x050800)
300  manager->sendCustomRequest(request, input->http_method.toLatin1(), request_content);
301 #else
302  QBuffer *buffer = new QBuffer;
303  buffer->setData(request_content);
304  buffer->open(QIODevice::ReadOnly);
305 
306  QNetworkReply* reply = manager->sendCustomRequest(request, input->http_method.toLatin1(), buffer);
307  buffer->setParent(reply);
308 #endif
309  }
310 
311 }
312 
313 void SWGHttpRequestWorker::on_manager_finished(QNetworkReply *reply) {
314  error_type = reply->error();
315  response = reply->readAll();
316  error_str = reply->errorString();
317 
318  reply->deleteLater();
319 
320  emit on_execution_finished(this);
321 }
323 
324 
325 }
void execute(SWGHttpRequestInput *input)
void add_file(QString variable_name, QString local_filename, QString request_filename, QString mime_type)
void on_execution_finished(SWGHttpRequestWorker *worker)
QMap< QString, QString > vars
Fixed< IntType, IntBits > arg(const std::complex< Fixed< IntType, IntBits > > &val)
Definition: fixed.h:2401
void on_manager_finished(QNetworkReply *reply)
QList< SWGHttpRequestInputFileElement > files
SWGHttpRequestVarLayout var_layout
static QSslConfiguration * sslDefaultConfiguration
int32_t i
Definition: decimators.h:244
QString http_attribute_encode(QString attribute_name, QString input)
QNetworkAccessManager * manager
QMap< QString, QString > headers
void add_var(QString key, QString value)
QNetworkReply::NetworkError error_type
SWGHttpRequestWorker(QObject *parent=0)