1 /** HTTP client class.
2  * https://github.com/azadkuh/qhttp
3  *
4  * @author amir zamani
5  * @version 2.0.0
6  * @date 2014-07-11
7   */
8 
9 #ifndef QHTTPCLIENT_HPP
10 #define QHTTPCLIENT_HPP
11 
12 ///////////////////////////////////////////////////////////////////////////////
13 #include "qhttpfwd.hpp"
14 
15 #include <QTcpSocket>
16 #include <QUrl>
17 
18 ///////////////////////////////////////////////////////////////////////////////
19 namespace qhttp {
20 namespace client {
21 ///////////////////////////////////////////////////////////////////////////////
22 using TRequstHandler   = std::function<void (QHttpRequest*)>;
23 using TResponseHandler = std::function<void (QHttpResponse*)>;
24 
25 /** a simple and async HTTP client class which sends a request to an HTTP server and parses the
26  *  corresponding response.
27  * This class internally handles the memory management and life cycle of QHttpRequest and
28  *  QHttpResponse instances. you do not have to manually delete or keep their pointers.
29  * in fact the QHttpRequest and QHttpResponse object will be deleted when the internal socket
30  *  disconnects.
31  */
32 class QHttpClient : public QObject
33 {
34     Q_OBJECT
35 
36     Q_PROPERTY(quint32 timeOut READ timeOut WRITE setTimeOut)
37 
38 public:
39     explicit    QHttpClient(QObject *parent = nullptr);
40 
41     virtual    ~QHttpClient();
42 
43     /** tries to connect to a HTTP server.
44      *  when the connection is made, the reqHandler will be called
45      *   and when the response is ready, resHandler will be called.
46      * @note httpConnected() and newResponse() won't be emitted.
47      *
48      * @param method an HTTP method, ex: GET, POST, ...
49      * @param url specifies server's address, port and optional path and query strings.
50      *  if url starts with socket:// the request will be made on QLocalSocket, otherwise
51      *  normal QTcpSocket will be used.
52      * @param resHandler response handler (a lambda, std::function object, ...)
53      * @return true if the url is valid or false (no connection will be made).
54      */
55     bool        request(THttpMethod method, QUrl url,
56                         const TRequstHandler& reqHandler,
57                         const TResponseHandler& resHandler);
58 
59     /** tries to connect to a HTTP server.
60      *  when the connection is made, a default request handler is called automatically (
61      *  simply calls req->end()) and when the response is ready, resHandler will be called.
62      * @note httpConnected() and newResponse() won't be emitted.
63      *
64      * @param method an HTTP method, ex: GET, POST, ...
65      * @param url specifies server's address, port and optional path and query strings.
66      * @param resHandler response handler (a lambda, std::function object, ...)
67      * @return true if the url is valid or false (no connection will be made).
68      */
request(THttpMethod method,QUrl url,const TResponseHandler & resHandler)69     inline bool request(THttpMethod method, QUrl url, const TResponseHandler& resHandler) {
70         return request(method, url, nullptr, resHandler);
71     }
72 
73     /** tries to connect to a HTTP server.
74      *  when the connection is made, creates and emits a QHttpRequest instance
75      *   by @sa httpConnected(QHttpRequest*).
76      * @note both httpConnected() and newResponse() may be emitted.
77      *
78      * @param method an HTTP method, ex: GET, POST, ...
79      * @param url specifies server's address, port and optional path and query strings.
80      * @return true if the url is valid or false (no connection will be made).
81      */
request(THttpMethod method,QUrl url)82     inline bool request(THttpMethod method, QUrl url) {
83         return request(method, url, nullptr, nullptr);
84     }
85 
86     /** checks if the connetion to the server is open. */
87     bool        isOpen() const;
88 
89     /** forcefully close the connection. */
90     void        killConnection();
91 
92 
93     /** returns time-out value [mSec] for ESTABLISHED connections (sockets).
94      *  @sa setTimeOut(). */
95     quint32     timeOut()const;
96 
97     /** set time-out for ESTABLISHED connections in miliseconds [mSec].
98      * each (already opened) connection will be forcefully closed after this timeout.
99      *  a zero (0) value disables timer for new connections. */
100     void        setTimeOut(quint32);
101 
102     /** set a time-out [mSec] for making a new connection (make a request).
103      * if connecting to server takes more than this time-out value,
104      *  the @sa timedOut(quint32) signal will be emitted and connection will be killed.
105      * 0 (default) timeout value means to disable this timer.
106      */
107     void        setConnectingTimeOut(quint32);
108 
109     template<class Handler>
setConnectingTimeOut(quint32 timeout,Handler && func)110     void        setConnectingTimeOut(quint32 timeout, Handler&& func) {
111         setConnectingTimeOut(timeout);
112         QObject::connect(this, &QHttpClient::connectingTimeOut,
113                 std::forward<Handler&&>(func)
114                 );
115     }
116 
117     /** returns the backend type of this client. */
118     TBackend    backendType() const;
119 
120     /** returns tcp socket of the connection if backend() == ETcpSocket. */
121     QTcpSocket* tcpSocket() const;
122 
123     /** returns local socket of the connection if backend() == ELocalSocket. */
124     QLocalSocket* localSocket() const;
125 
126 signals:
127     /** emitted when a new HTTP connection to the server is established.
128      * if you overload onRequestReady this signal won't be emitted.
129      * @sa onRequestReady
130      * @sa QHttpRequest
131      */
132     void        httpConnected(QHttpRequest* req);
133 
134     /** emitted when a new response is received from the server.
135      * if you overload onResponseReady this signal won't be emitted.
136      * @sa onResponseReady
137      * @sa QHttpResponse
138      */
139     void        newResponse(QHttpResponse* res);
140 
141     /** emitted when the HTTP connection drops or being disconnected. */
142     void        disconnected();
143 
144     /// emitted when fails to connect to a HTTP server. @sa setConnectingTimeOut()
145     void        connectingTimeOut();
146 
147 
148 protected:
149     /** called when a new HTTP connection is established.
150      * you can overload this method, the default implementaion only emits connected().
151      * @param req use this request instance for assinging the
152      *   request headers and sending optional body.
153      * @see httpConnected(QHttpRequest*)
154      */
155     virtual void onRequestReady(QHttpRequest* req);
156 
157     /** called when a new response is received from the server.
158      *  you can overload this method, the default implementaion only emits newResponse().
159      * @param res use this instance for reading incoming response.
160      * @see newResponse(QHttpResponse*)
161      */
162     virtual void onResponseReady(QHttpResponse* res);
163 
164 protected:
165     explicit    QHttpClient(QHttpClientPrivate&, QObject*);
166 
167     void        timerEvent(QTimerEvent*) override;
168 
169     Q_DECLARE_PRIVATE(QHttpClient)
170     Q_DISABLE_COPY(QHttpClient)
171     QScopedPointer<QHttpClientPrivate>  d_ptr;
172 };
173 
174 ///////////////////////////////////////////////////////////////////////////////
175 } // namespace client
176 } // namespace qhttp
177 ///////////////////////////////////////////////////////////////////////////////
178 #endif // define QHTTPCLIENT_HPP
179