1 /** @file httpwriter.hxx
2  *
3  * @copyright (C) 2016
4  * @date 2016.05.26
5  * @version 1.0.0
6  * @author amir zamani <azadkuh@live.com>
7  *
8  */
9 
10 #ifndef __QHTTP_HTTPWRITER_HXX__
11 #define __QHTTP_HTTPWRITER_HXX__
12 
13 #include "qhttpbase.hpp"
14 
15 ///////////////////////////////////////////////////////////////////////////////
16 namespace qhttp {
17 namespace details {
18 ///////////////////////////////////////////////////////////////////////////////
19 
20 // usage in client::QHttpRequest, server::QHttpResponse
21 template<class TBase, class TImpl>
22 class HttpWriter : public TBase
23 {
24 public:
addHeader(const QByteArray & field,const QByteArray & value)25     bool addHeader(const QByteArray &field, const QByteArray &value) {
26         if ( ifinished )
27             return false;
28 
29         TBase::iheaders.insert(field.toLower(), value);
30         return true;
31     }
32 
writeHeader(const QByteArray & field,const QByteArray & value)33     bool writeHeader(const QByteArray& field, const QByteArray& value) {
34         if ( ifinished )
35             return false;
36 
37         QByteArray buffer = QByteArray(field)
38                             .append(": ")
39                             .append(value)
40                             .append("\r\n");
41 
42         isocket.writeRaw(buffer);
43         return true;
44     }
45 
writeData(const QByteArray & data)46     bool writeData(const QByteArray& data) {
47         if ( ifinished )
48             return false;
49 
50         ensureWritingHeaders();
51         isocket.writeRaw(data);
52         return true;
53     }
54 
endPacket(const QByteArray & data)55     bool endPacket(const QByteArray& data) {
56         if ( !writeData(data) )
57             return false;
58 
59         isocket.flush();
60         ifinished = true;
61         return true;
62     }
63 
ensureWritingHeaders()64     void ensureWritingHeaders() {
65         if ( ifinished    ||    iheaderWritten )
66             return;
67 
68         TImpl* me = static_cast<TImpl*>(this);
69         isocket.writeRaw(me->makeTitle());
70         writeHeaders();
71 
72         iheaderWritten = true;
73     }
74 
writeHeaders(bool doFlush=false)75     void writeHeaders(bool doFlush = false) {
76         if ( ifinished    ||    iheaderWritten )
77             return;
78 
79         if ( TBase::iheaders.keyHasValue("connection", "keep-alive") )
80             ikeepAlive = true;
81         else
82             TBase::iheaders.insert("connection", "close");
83 
84         TImpl* me = static_cast<TImpl*>(this);
85         me->prepareHeadersToWrite();
86 
87         TBase::iheaders.forEach([this](const auto& cit) {
88             this->writeHeader(cit.key(), cit.value());
89         });
90 
91         isocket.writeRaw("\r\n");
92         if ( doFlush )
93             isocket.flush();
94     }
95 
96 public:
97     QSocket isocket;
98 
99     bool    ifinished      = false;
100     bool    iheaderWritten = false;
101     bool    ikeepAlive     = false;
102 };
103 
104 
105 ///////////////////////////////////////////////////////////////////////////////
106 } // namespace details
107 } // namespace qhttp
108 ///////////////////////////////////////////////////////////////////////////////
109 #endif // __QHTTP_HTTPWRITER_HXX__
110