1 #include "http.h"
2 
3 #include "networkhttpreply.h"
4 
5 namespace {
6 
networkAccessManager()7 QNetworkAccessManager *networkAccessManager() {
8     static thread_local QNetworkAccessManager *nam = new QNetworkAccessManager();
9     return nam;
10 }
11 
12 int defaultReadTimeout = 10000;
13 int defaultMaxRetries = 3;
14 } // namespace
15 
Http()16 Http::Http()
17     : requestHeaders(getDefaultRequestHeaders()), readTimeout(defaultReadTimeout),
18       maxRetries(defaultMaxRetries) {}
19 
setRequestHeaders(const QMap<QByteArray,QByteArray> & headers)20 void Http::setRequestHeaders(const QMap<QByteArray, QByteArray> &headers) {
21     requestHeaders = headers;
22 }
23 
getRequestHeaders()24 QMap<QByteArray, QByteArray> &Http::getRequestHeaders() {
25     return requestHeaders;
26 }
27 
addRequestHeader(const QByteArray & name,const QByteArray & value)28 void Http::addRequestHeader(const QByteArray &name, const QByteArray &value) {
29     requestHeaders.insert(name, value);
30 }
31 
setReadTimeout(int timeout)32 void Http::setReadTimeout(int timeout) {
33     readTimeout = timeout;
34 }
35 
instance()36 Http &Http::instance() {
37     static Http i;
38     return i;
39 }
40 
getDefaultRequestHeaders()41 const QMap<QByteArray, QByteArray> &Http::getDefaultRequestHeaders() {
42     static const QMap<QByteArray, QByteArray> defaultRequestHeaders = [] {
43         QMap<QByteArray, QByteArray> h;
44         h.insert("Accept-Charset", "utf-8");
45         h.insert("Connection", "Keep-Alive");
46         return h;
47     }();
48     return defaultRequestHeaders;
49 }
50 
setDefaultReadTimeout(int timeout)51 void Http::setDefaultReadTimeout(int timeout) {
52     defaultReadTimeout = timeout;
53 }
54 
networkReply(const HttpRequest & req)55 QNetworkReply *Http::networkReply(const HttpRequest &req) {
56     QNetworkRequest request(req.url);
57 
58     QMap<QByteArray, QByteArray> &headers = requestHeaders;
59     if (!req.headers.isEmpty()) headers = req.headers;
60 
61     QMap<QByteArray, QByteArray>::const_iterator it;
62     for (it = headers.constBegin(); it != headers.constEnd(); ++it)
63         request.setRawHeader(it.key(), it.value());
64 
65     if (req.offset > 0)
66         request.setRawHeader("Range", QStringLiteral("bytes=%1-").arg(req.offset).toUtf8());
67 
68     QNetworkAccessManager *manager = networkAccessManager();
69 
70     QNetworkReply *networkReply = nullptr;
71     switch (req.operation) {
72     case QNetworkAccessManager::GetOperation:
73         networkReply = manager->get(request);
74         break;
75 
76     case QNetworkAccessManager::HeadOperation:
77         networkReply = manager->head(request);
78         break;
79 
80     case QNetworkAccessManager::PostOperation:
81         networkReply = manager->post(request, req.body);
82         break;
83 
84     case QNetworkAccessManager::PutOperation:
85         networkReply = manager->put(request, req.body);
86         break;
87 
88     case QNetworkAccessManager::DeleteOperation:
89         networkReply = manager->deleteResource(request);
90         break;
91 
92     default:
93         qWarning() << "Unknown operation:" << req.operation;
94     }
95 
96     return networkReply;
97 }
98 
request(const HttpRequest & req)99 HttpReply *Http::request(const HttpRequest &req) {
100     return new NetworkHttpReply(req, *this);
101 }
102 
request(const QUrl & url,QNetworkAccessManager::Operation operation,const QByteArray & body,uint offset)103 HttpReply *Http::request(const QUrl &url,
104                          QNetworkAccessManager::Operation operation,
105                          const QByteArray &body,
106                          uint offset) {
107     HttpRequest req;
108     req.url = url;
109     req.operation = operation;
110     req.body = body;
111     req.offset = offset;
112     return request(req);
113 }
114 
get(const QUrl & url)115 HttpReply *Http::get(const QUrl &url) {
116     return request(url, QNetworkAccessManager::GetOperation);
117 }
118 
head(const QUrl & url)119 HttpReply *Http::head(const QUrl &url) {
120     return request(url, QNetworkAccessManager::HeadOperation);
121 }
122 
post(const QUrl & url,const QMap<QString,QString> & params)123 HttpReply *Http::post(const QUrl &url, const QMap<QString, QString> &params) {
124     QByteArray body;
125     QMapIterator<QString, QString> i(params);
126     while (i.hasNext()) {
127         i.next();
128         body += QUrl::toPercentEncoding(i.key()) + '=' + QUrl::toPercentEncoding(i.value()) + '&';
129     }
130     HttpRequest req;
131     req.url = url;
132     req.operation = QNetworkAccessManager::PostOperation;
133     req.body = body;
134     req.headers = requestHeaders;
135     req.headers.insert("Content-Type", "application/x-www-form-urlencoded");
136     return request(req);
137 }
138 
post(const QUrl & url,const QByteArray & body,const QByteArray & contentType)139 HttpReply *Http::post(const QUrl &url, const QByteArray &body, const QByteArray &contentType) {
140     HttpRequest req;
141     req.url = url;
142     req.operation = QNetworkAccessManager::PostOperation;
143     req.body = body;
144     req.headers = requestHeaders;
145     QByteArray cType = contentType;
146     if (cType.isEmpty()) cType = "application/x-www-form-urlencoded";
147     req.headers.insert("Content-Type", cType);
148     return request(req);
149 }
150 
151 
put(const QUrl & url,const QByteArray & body,const QByteArray & contentType)152 HttpReply *Http::put(const QUrl &url, const QByteArray &body, const QByteArray &contentType) {
153 	HttpRequest req;
154 	req.url = url;
155 	req.operation = QNetworkAccessManager::PutOperation;
156 	req.body = body;
157 	req.headers = requestHeaders;
158 	QByteArray cType = contentType;
159 	if (cType.isEmpty()) cType = "application/x-www-form-urlencoded";
160 	req.headers.insert("Content-Type", cType);
161 	return request(req);
162 }
163 
164 
deleteResource(const QUrl & url)165 HttpReply *Http::deleteResource(const QUrl &url) {
166 	HttpRequest req;
167 	req.url = url;
168 	req.operation = QNetworkAccessManager::DeleteOperation;
169 	req.headers = requestHeaders;
170 	return request(req);
171 }
172 
getMaxRetries() const173 int Http::getMaxRetries() const {
174     return maxRetries;
175 }
176 
setMaxRetries(int value)177 void Http::setMaxRetries(int value) {
178     maxRetries = value;
179 }
180