File indexing completed on 2025-01-26 04:24:52
0001 /* 0002 * Copyright 2011 Nikhil Marathe <nsm.nikhil@gmail.com> 0003 * 0004 * Permission is hereby granted, free of charge, to any person obtaining a copy 0005 * of this software and associated documentation files (the "Software"), to 0006 * deal in the Software without restriction, including without limitation the 0007 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 0008 * sell copies of the Software, and to permit persons to whom the Software is 0009 * furnished to do so, subject to the following conditions: 0010 * 0011 * The above copyright notice and this permission notice shall be included in 0012 * all copies or substantial portions of the Software. 0013 * 0014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 0019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 0020 * IN THE SOFTWARE. 0021 */ 0022 0023 #include "qhttpresponse.h" 0024 0025 #include <QDateTime> 0026 0027 #include "qhttpserver.h" 0028 #include "qhttpconnection.h" 0029 0030 QHttpResponse::QHttpResponse(QHttpConnection *connection) 0031 // TODO: parent child relation 0032 : QObject(0) 0033 , m_connection(connection) 0034 , m_headerWritten(false) 0035 , m_sentConnectionHeader(false) 0036 , m_sentContentLengthHeader(false) 0037 , m_sentTransferEncodingHeader(false) 0038 , m_sentDate(false) 0039 , m_keepAlive(true) 0040 , m_last(false) 0041 , m_useChunkedEncoding(false) 0042 , m_finished(false) 0043 { 0044 } 0045 0046 QHttpResponse::~QHttpResponse() 0047 { 0048 } 0049 0050 void QHttpResponse::setHeader(const QString &field, const QString &value) 0051 { 0052 if(m_finished) { 0053 return; 0054 } 0055 0056 m_headers[field] = value; 0057 } 0058 0059 void QHttpResponse::writeHeader(const char *field, const QString &value) 0060 { 0061 if(m_finished) { 0062 return; 0063 } 0064 0065 m_connection->write(field); 0066 m_connection->write(": "); 0067 m_connection->write(value.toUtf8()); 0068 m_connection->write("\r\n"); 0069 } 0070 0071 void QHttpResponse::writeHeaders() 0072 { 0073 if(m_finished) { 0074 return; 0075 } 0076 0077 foreach(QString name, m_headers.keys()) 0078 { 0079 QString value = m_headers[name]; 0080 if( name.compare("connection", Qt::CaseInsensitive) == 0 ) 0081 { 0082 m_sentConnectionHeader = true; 0083 if( value == "close" ) 0084 m_last = true; 0085 else 0086 m_keepAlive = true; 0087 } 0088 else if( name.compare("transfer-encoding", Qt::CaseInsensitive) == 0 ) 0089 { 0090 m_sentTransferEncodingHeader = true; 0091 if( value == "chunked" ) 0092 m_useChunkedEncoding = true; 0093 } 0094 else if( name.compare("content-length", Qt::CaseInsensitive) == 0 ) 0095 { 0096 m_sentContentLengthHeader = true; 0097 } 0098 else if( name.compare("date", Qt::CaseInsensitive) == 0 ) 0099 { 0100 m_sentDate = true; 0101 } 0102 //TODO: Expect case 0103 0104 writeHeader(name.toLatin1(), value.toLatin1()); 0105 } 0106 0107 if( !m_sentConnectionHeader ) 0108 { 0109 if( m_keepAlive && 0110 ( m_sentContentLengthHeader || m_useChunkedEncoding ) ) 0111 { 0112 writeHeader("Connection", "keep-alive"); 0113 } 0114 else 0115 { 0116 m_last = true; 0117 writeHeader("Connection", "close"); 0118 } 0119 } 0120 0121 if( !m_sentContentLengthHeader && !m_sentTransferEncodingHeader ) 0122 { 0123 if( m_useChunkedEncoding ) 0124 writeHeader("Transfer-Encoding", "chunked"); 0125 else 0126 m_last = true; 0127 } 0128 0129 if( !m_sentDate ) 0130 { 0131 writeHeader("Date", QDateTime::currentDateTimeUtc().toString("ddd, dd MMM yyyy hh:mm:ss G'M'T")); 0132 } 0133 } 0134 0135 void QHttpResponse::writeHead(int status) 0136 { 0137 if(m_finished) { 0138 return; 0139 } 0140 0141 if( m_headerWritten ) return; 0142 0143 m_connection->write(QString("HTTP/1.1 %1 %2\r\n").arg(status).arg(STATUS_CODES[status]).toLatin1()); 0144 0145 writeHeaders(); 0146 0147 m_connection->write("\r\n"); 0148 m_headerWritten = true; 0149 } 0150 0151 void QHttpResponse::write(const QByteArray &data) 0152 { 0153 if(m_finished) { 0154 return; 0155 } 0156 0157 if( !m_headerWritten ) 0158 { 0159 qDebug() << "You MUST call writeHead() before writing body data"; 0160 return; 0161 } 0162 0163 m_connection->write(data); 0164 } 0165 0166 void QHttpResponse::write(const QString &data) 0167 { 0168 if(m_finished) { 0169 return; 0170 } 0171 0172 m_connection->write(data.toUtf8()); 0173 } 0174 0175 void QHttpResponse::write_b64(const QByteArray &data) 0176 { 0177 this->write(QByteArray::fromBase64(data)); 0178 } 0179 0180 void QHttpResponse::end(const QString &data) 0181 { 0182 if(m_finished) { 0183 return; 0184 } 0185 0186 write(data); 0187 0188 m_finished = true; 0189 0190 Q_EMIT done(); 0191 deleteLater(); 0192 // TODO: end connection and delete ourselves 0193 } 0194 0195 void QHttpResponse::connectionClosed() 0196 { 0197 m_finished = true; 0198 deleteLater(); 0199 }