1 /**
2   @file
3   @author Stefan Frings
4 */
5 
6 #include "requestmapper.h"
7 #include "static.h"
8 #include "staticfilecontroller.h"
9 
10 #include "controllers/versioncontroller.h"
11 
12 #include "controllers/v1/librariescontroller.h"
13 #include "controllers/v1/foldercontroller.h"
14 #include "controllers/v1/covercontroller.h"
15 #include "controllers/v1/comiccontroller.h"
16 #include "controllers/v1/folderinfocontroller.h"
17 #include "controllers/v1/pagecontroller.h"
18 #include "controllers/v1/updatecomiccontroller.h"
19 #include "controllers/v1/errorcontroller.h"
20 #include "controllers/v1/comicdownloadinfocontroller.h"
21 #include "controllers/v1/synccontroller.h"
22 
23 #include "controllers/v2/librariescontroller_v2.h"
24 #include "controllers/v2/covercontroller_v2.h"
25 #include "controllers/v2/comiccontroller_v2.h"
26 #include "controllers/v2/folderinfocontroller_v2.h"
27 #include "controllers/v2/pagecontroller_v2.h"
28 #include "controllers/v2/updatecomiccontroller_v2.h"
29 #include "controllers/v2/errorcontroller_v2.h"
30 #include "controllers/v2/comicdownloadinfocontroller_v2.h"
31 #include "controllers/v2/synccontroller_v2.h"
32 #include "controllers/v2/foldercontentcontroller_v2.h"
33 #include "controllers/v2/tagscontroller_v2.h"
34 #include "controllers/v2/tagcontentcontroller_v2.h"
35 #include "controllers/v2/taginfocontroller_v2.h"
36 #include "controllers/v2/favoritescontroller_v2.h"
37 #include "controllers/v2/readingcomicscontroller_v2.h"
38 #include "controllers/v2/readinglistscontroller_v2.h"
39 #include "controllers/v2/readinglistcontentcontroller_v2.h"
40 #include "controllers/v2/readinglistinfocontroller_v2.h"
41 #include "controllers/v2/comicfullinfocontroller_v2.h"
42 #include "controllers/v2/comiccontrollerinreadinglist_v2.h"
43 
44 #include "db_helper.h"
45 #include "yacreader_libraries.h"
46 
47 #include "yacreader_http_session.h"
48 
49 #include "QsLog.h"
50 
51 using stefanfrings::HttpRequest;
52 using stefanfrings::HttpRequestHandler;
53 using stefanfrings::HttpResponse;
54 using stefanfrings::HttpSession;
55 
56 QMutex RequestMapper::mutex;
57 
RequestMapper(QObject * parent)58 RequestMapper::RequestMapper(QObject *parent)
59     : HttpRequestHandler(parent) { }
60 
loadSessionV1(HttpRequest & request,HttpResponse & response)61 void RequestMapper::loadSessionV1(HttpRequest &request, HttpResponse &response)
62 {
63     QMutexLocker locker(&mutex);
64 
65     HttpSession session = Static::sessionStore->getSession(request, response);
66     if (session.contains("ySession")) //session is already alive check if it is needed to update comics
67     {
68         auto ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
69 
70         QString postData = QString::fromUtf8(request.getBody());
71 
72         if (postData.contains("currentPage"))
73             return;
74 
75         if (postData.length() > 0) {
76 
77             QList<QString> data = postData.split("\n");
78             if (data.length() > 2) {
79                 ySession->setDeviceType(data.at(0).split(":").at(1));
80                 ySession->setDisplayType(data.at(1).split(":").at(1));
81                 QList<QString> comics = data.at(2).split(":").at(1).split("\t");
82                 ySession->clearComics();
83                 foreach (QString hash, comics) {
84                     ySession->setComicOnDevice(hash);
85                 }
86             } else {
87                 if (data.length() > 1) {
88                     ySession->setDeviceType(data.at(0).split(":").at(1));
89                     ySession->setDisplayType(data.at(1).split(":").at(1));
90                 }
91             }
92         }
93     } else {
94         auto ySession = new YACReaderHttpSession(this);
95 
96         Static::yacreaderSessionStore->addYACReaderHttpSession(session.getId(), ySession);
97 
98         session.set("ySession", "ok");
99 
100         QString postData = QString::fromUtf8(request.getBody());
101         //response.writeText(postData);
102 
103         QList<QString> data = postData.split("\n");
104 
105         if (data.length() > 2) {
106             auto deviceTypeData = data.at(0).split(":");
107             if (deviceTypeData.length() == 2) {
108                 ySession->setDeviceType(deviceTypeData.at(1));
109             }
110 
111             auto displayTypeData = data.at(1).split(":");
112             if (displayTypeData.length() == 2) {
113                 ySession->setDisplayType(displayTypeData.at(1));
114             }
115 
116             auto comicsData = data.at(2).split(":");
117             if (comicsData.length() == 2) {
118                 QList<QString> comics = comicsData.at(1).split("\t");
119                 foreach (QString hash, comics) {
120                     ySession->setComicOnDevice(hash);
121                 }
122             }
123         } else //values by default, only for debug purposes.
124         {
125             ySession->setDeviceType("ipad");
126             ySession->setDisplayType("@2x");
127         }
128     }
129 }
130 
loadSessionV2(HttpRequest & request,HttpResponse &)131 void RequestMapper::loadSessionV2(HttpRequest &request, HttpResponse & /* response */)
132 {
133     QMutexLocker locker(&mutex);
134 
135     QByteArray token = request.getHeader("x-request-id");
136 
137     if (token.isEmpty()) {
138         return;
139     }
140 
141     auto yRecoveredSession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(token);
142 
143     if (yRecoveredSession == nullptr) //session is already alive check if it is needed to update comics
144     {
145         auto ySession = new YACReaderHttpSession(this);
146 
147         Static::yacreaderSessionStore->addYACReaderHttpSession(token, ySession);
148     }
149 }
150 
service(HttpRequest & request,HttpResponse & response)151 void RequestMapper::service(HttpRequest &request, HttpResponse &response)
152 {
153     QByteArray path = request.getPath();
154 
155     QLOG_TRACE() << "RequestMapper: path=" << path.data();
156     QLOG_TRACE() << "X-Request-Id: " << request.getHeader("x-request-id");
157 
158     if (path.startsWith("/v2")) {
159         serviceV2(request, response);
160     } else {
161         serviceV1(request, response);
162     }
163 }
164 
serviceV1(HttpRequest & request,HttpResponse & response)165 void RequestMapper::serviceV1(HttpRequest &request, HttpResponse &response)
166 {
167     QByteArray path = request.getPath();
168 
169     QRegExp folder("/library/.+/folder/[0-9]+/?"); //get comic content
170     QRegExp folderInfo("/library/.+/folder/[0-9]+/info/?"); //get folder info
171     QRegExp comicDownloadInfo("/library/.+/comic/[0-9]+/?"); //get comic info (basic/download info)
172     QRegExp comicFullInfo("/library/.+/comic/[0-9]+/info/?"); //get comic info (full info)
173     QRegExp comicOpen("/library/.+/comic/[0-9]+/remote/?"); //the server will open for reading the comic
174     QRegExp comicUpdate("/library/.+/comic/[0-9]+/update/?"); //get comic info
175     QRegExp comicClose("/library/.+/comic/[0-9]+/close/?"); //the server will close the comic and free memory
176     QRegExp cover("/library/.+/cover/[0-9a-f]+.jpg"); //get comic cover (navigation)
177     QRegExp comicPage("/library/.+/comic/[0-9]+/page/[0-9]+/?"); //get comic page
178     QRegExp comicPageRemote("/library/.+/comic/[0-9]+/page/[0-9]+/remote?"); //get comic page (remote reading)
179 
180     QRegExp sync("/sync");
181 
182     QRegExp library("/library/([0-9]+)/.+"); //permite verificar que la biblioteca solicitada existe
183 
184     path = QUrl::fromPercentEncoding(path).toUtf8();
185 
186     if (!sync.exactMatch(path)) //no session is needed for syncback info, until security will be added
187         loadSessionV1(request, response);
188 
189     //primera petición, se ha hecho un post, se sirven las bibliotecas si la seguridad mediante login no está habilitada
190     if (path == "/") //Don't send data to the server using '/' !!!!
191     {
192         LibrariesController().service(request, response);
193     } else {
194         if (sync.exactMatch(path))
195             SyncController().service(request, response);
196         else {
197             //se comprueba que la sesión sea la correcta con el fin de evitar accesos no autorizados
198             HttpSession session = Static::sessionStore->getSession(request, response, false);
199             if (!session.isNull() && session.contains("ySession")) {
200                 if (library.indexIn(path) != -1 && DBHelper::getLibraries().contains(library.cap(1).toInt())) {
201                     //listar el contenido del folder
202                     if (folder.exactMatch(path)) {
203                         FolderController().service(request, response);
204                     } else if (folderInfo.exactMatch(path)) {
205                         FolderInfoController().service(request, response);
206                     } else if (cover.exactMatch(path)) {
207                         CoverController().service(request, response);
208                     } else if (comicDownloadInfo.exactMatch(path)) {
209                         ComicDownloadInfoController().service(request, response);
210                     } else if (comicFullInfo.exactMatch(path) || comicOpen.exactMatch(path)) //start download or start remote reading
211                     {
212                         ComicController().service(request, response);
213                     } else if (comicPage.exactMatch(path) || comicPageRemote.exactMatch(path)) {
214                         PageController().service(request, response);
215                     } else if (comicUpdate.exactMatch(path)) {
216                         UpdateComicController().service(request, response);
217                     }
218                 } else {
219                     //response.writeText(library.cap(1));
220                     Static::staticFileController->service(request, response);
221                 }
222             } else //acceso no autorizado, redirección
223             {
224                 ErrorController(300).service(request, response);
225             }
226         }
227     }
228 }
229 
serviceV2(HttpRequest & request,HttpResponse & response)230 void RequestMapper::serviceV2(HttpRequest &request, HttpResponse &response)
231 {
232     QByteArray path = request.getPath();
233 
234     QRegExp folderInfo("/v2/library/.+/folder/[0-9]+/info/?"); //get folder info
235     QRegExp comicDownloadInfo("/v2/library/.+/comic/[0-9]+/info/?"); //get comic info (full download info)
236     QRegExp comicOpenForDownloading("/v2/library/.+/comic/[0-9]+/?"); //get comic info (full info + opening)
237     QRegExp comicOpenForRemoteReading("/v2/library/.+/comic/[0-9]+/remote/?"); //the server will open for reading the comic
238     QRegExp comicOpenForRemoteReadingInAReadingList("/v2/library/.+/reading_list/[0-9]+/comic/[0-9]+/remote/?"); //the server will open for reading the comic
239     QRegExp comicFullInfo("/v2/library/.+/comic/[0-9]+/fullinfo/?"); //get comic info
240     QRegExp comicUpdate("/v2/library/.+/comic/[0-9]+/update/?"); //get comic info
241     QRegExp comicClose("/v2/library/.+/comic/[0-9]+/close/?"); //the server will close the comic and free memory
242     QRegExp cover("/v2/library/.+/cover/[0-9a-f]+.jpg"); //get comic cover (navigation)
243     QRegExp comicPage("/v2/library/.+/comic/[0-9]+/page/[0-9]+/?"); //get comic page
244     QRegExp comicPageRemote("/v2/library/.+/comic/[0-9]+/page/[0-9]+/remote?"); //get comic page (remote reading)
245     QRegExp serverVersion("/v2/version/?");
246     QRegExp folderContent("/v2/library/.+/folder/[0-9]+/content/?");
247     QRegExp favs("/v2/library/.+/favs/?");
248     QRegExp reading("/v2/library/.+/reading/?");
249     QRegExp tags("/v2/library/.+/tags/?");
250     QRegExp tagContent("/v2/library/.+/tag/[0-9]+/content/?");
251     QRegExp tagInfo("/v2/library/.+/tag/[0-9]+/info/?");
252     QRegExp readingLists("/v2/library/.+/reading_lists/?");
253     QRegExp readingListContent("/v2/library/.+/reading_list/[0-9]+/content/?");
254     QRegExp readingListInfo("/v2/library/.+/reading_list/[0-9]+/info/?");
255 
256     QRegExp sync("/v2/sync");
257 
258     QRegExp library("/v2/library/([0-9]+)/.+"); //permite verificar que la biblioteca solicitada existe
259 
260     path = QUrl::fromPercentEncoding(path).toUtf8();
261 
262     if (!sync.exactMatch(path)) //no session is needed for syncback info, until security will be added
263         loadSessionV2(request, response);
264 
265     //primera petición, se ha hecho un post, se sirven las bibliotecas si la seguridad mediante login no está habilitada
266     if (path == "/v2/libraries") //Don't send data to the server using '/' !!!!
267     {
268         LibrariesControllerV2().service(request, response);
269     } else {
270         if (serverVersion.exactMatch(path)) {
271             VersionController().service(request, response);
272         } else if (sync.exactMatch(path)) {
273             SyncControllerV2().service(request, response);
274         } else {
275             if (library.indexIn(path) != -1 && DBHelper::getLibraries().contains(library.cap(1).toInt())) {
276                 if (folderInfo.exactMatch(path)) {
277                     FolderInfoControllerV2().service(request, response);
278                 } else if (cover.exactMatch(path)) {
279                     CoverControllerV2().service(request, response);
280                 } else if (comicDownloadInfo.exactMatch(path)) {
281                     ComicDownloadInfoControllerV2().service(request, response);
282                 } else if (comicOpenForRemoteReadingInAReadingList.exactMatch(path)) {
283                     ComicControllerInReadingListV2().service(request, response);
284                 } else if (comicOpenForDownloading.exactMatch(path) || comicOpenForRemoteReading.exactMatch(path)) { //start download or start remote reading
285                     ComicControllerV2().service(request, response);
286                 } else if (comicFullInfo.exactMatch(path)) {
287                     ComicFullinfoController_v2().service(request, response);
288                 } else if (comicPage.exactMatch(path) || comicPageRemote.exactMatch(path)) {
289                     PageControllerV2().service(request, response);
290                 } else if (comicUpdate.exactMatch(path)) {
291                     UpdateComicControllerV2().service(request, response);
292                 } else if (folderContent.exactMatch(path)) {
293                     FolderContentControllerV2().service(request, response);
294                 } else if (tags.exactMatch(path)) {
295                     TagsControllerV2().service(request, response);
296                 } else if (tagContent.exactMatch(path)) {
297                     TagContentControllerV2().service(request, response);
298                 } else if (favs.exactMatch(path)) {
299                     FavoritesControllerV2().service(request, response);
300                 } else if (reading.exactMatch(path)) {
301                     ReadingComicsControllerV2().service(request, response);
302                 } else if (readingLists.exactMatch(path)) {
303                     ReadingListsControllerV2().service(request, response);
304                 } else if (readingListContent.exactMatch(path)) {
305                     ReadingListContentControllerV2().service(request, response);
306                 } else if (readingListInfo.exactMatch(path)) {
307                     ReadingListInfoControllerV2().service(request, response);
308                 } else if (tagInfo.exactMatch(path)) {
309                     TagInfoControllerV2().service(request, response);
310                 }
311             } else {
312                 //response.writeText(library.cap(1));
313                 Static::staticFileController->service(request, response);
314             }
315         }
316     }
317 }
318