1 /*
2     SPDX-FileCopyrightText: 2008 Joris Guisson <joris.guisson@gmail.com>
3     SPDX-FileCopyrightText: 2008 Ivan Vasic <ivasic@gmail.com>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 #ifndef BTHTTPCONNECTION_H
8 #define BTHTTPCONNECTION_H
9 
10 #include <QMutex>
11 #include <QTimer>
12 #include <QUrl>
13 #include <net/addressresolver.h>
14 #include <net/streamsocket.h>
15 
16 class QUrl;
17 
18 namespace bt
19 {
20 /**
21     @author Joris Guisson
22 
23     HTTP connection for webseeding. We do not use KIO here, because we want to be able to apply
24     the maximum upload and download rate to webseeds;
25 */
26 class HttpConnection : public QObject, public net::SocketReader, public net::StreamSocketListener
27 {
28     Q_OBJECT
29 public:
30     HttpConnection();
31     ~HttpConnection() override;
32 
33     /// Get the last http response code
responseCode()34     int responseCode() const
35     {
36         return response_code;
37     }
38 
39     /// Is this connection redirected
isRedirected()40     bool isRedirected() const
41     {
42         return redirected;
43     }
44 
45     /// Get the redirected url
redirectedUrl()46     QUrl redirectedUrl() const
47     {
48         return redirected_url;
49     }
50 
51     /**
52      * Set the group ID's of the socket
53      * @param up Upload group id
54      * @param down Download group id
55      */
56     void setGroupIDs(Uint32 up, Uint32 down);
57 
58     /**
59      * Connect to a webseed
60      * @param url Url of the webseeder
61      */
62     void connectTo(const QUrl &url);
63 
64     /**
65      * Connect to a proxy.
66      * @param proxy The HTTP proxy to use (null means don't use any)
67      * @param proxy_port The port of the HTTP proxy
68      */
69     void connectToProxy(const QString &proxy, Uint16 proxy_port);
70 
71     /// Check if the connection is OK
72     bool ok() const;
73 
74     /// See if we are connected
75     bool connected() const;
76 
77     /// Has the connection been closed
78     bool closed() const;
79 
80     /// Ready to do another request
81     bool ready() const;
82 
83     /**
84      * Do a HTTP GET request
85      * @param path The path of the file
86      * @param query The query string for the url
87      * @param start Offset into file
88      * @param len Length of data to download
89      */
90     bool get(const QString &host, const QString &path, const QString &query, bt::Uint64 start, bt::Uint64 len);
91 
92     void onDataReady(Uint8 *buf, Uint32 size) override;
93     void connectFinished(bool succeeded) override;
94     void dataSent() override;
95 
96     /**
97      * Get some part of the
98      * @param data Bytearray to copy the data into
99      * @return true if data was filled in
100      */
101     bool getData(QByteArray &data);
102 
103     /// Get the current download rate
104     int getDownloadRate() const;
105 
106     /// Get the status string
107     const QString getStatusString() const;
108 
109 private:
110     void hostResolved(net::AddressResolver *ar);
111     void connectTimeout();
112     void replyTimeout();
113 
114 Q_SIGNALS:
115     void startReplyTimer(int timeout);
116     void stopReplyTimer();
117     void stopConnectTimer();
118 
119 private:
120     enum State {
121         IDLE,
122         RESOLVING,
123         CONNECTING,
124         ACTIVE,
125         ERROR,
126         CLOSED,
127     };
128 
129     struct HttpGet {
130         QString host;
131         QString path;
132         QString query;
133         bt::Uint64 start;
134         bt::Uint64 len;
135         bt::Uint64 data_received;
136         QByteArray buffer;
137         QByteArray piece_data;
138         bool response_header_received;
139         bool request_sent;
140         QString failure_reason;
141         bool redirected;
142         QUrl redirected_to;
143         bt::Uint64 content_length;
144         int response_code;
145 
146         HttpGet(const QString &host, const QString &path, const QString &query, bt::Uint64 start, bt::Uint64 len, bool using_proxy);
147         virtual ~HttpGet();
148 
149         bool onDataReady(Uint8 *buf, Uint32 size);
finishedHttpGet150         bool finished() const
151         {
152             return data_received >= len;
153         }
154     };
155 
156     net::StreamSocket *sock;
157     State state;
158     mutable QMutex mutex;
159     HttpGet *request;
160     bool using_proxy;
161     QString status;
162     QTimer connect_timer;
163     QTimer reply_timer;
164     Uint32 up_gid, down_gid;
165     bool close_when_finished;
166     bool redirected;
167     QUrl redirected_url;
168     int response_code;
169 };
170 }
171 
172 #endif
173