ClientSession.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "BodyReader.h"
00025 #include "BodyWriter.h"
00026 #include "ClientSession.h"
00027 #include "HeaderReader.h"
00028 #include "HeaderWriter.h"
00029 #include "RequestHeader.h"
00030 #include "ResponseHeader.h"
00031 #include "Imports.cpp"
00032 
00033 using namespace Http;
00034 
00035 namespace Http {
00036 
00037 enum Constants
00038 {
00039     MajorVersion    = 1,
00040     MinorVersion    = 1
00041 };
00042 
00043 class ClientSessionPrivate
00044 {
00045 public:
00046     Connection      *connection;
00047     HeaderReader    *headerReader;
00048     HeaderWriter    *headerWriter;
00049     BodyReader      *bodyReader;
00050     BodyWriter      *bodyWriter;
00051 
00052     QByteArray      requestBody;
00053     QBuffer         postBuffer;
00054 
00055     ClientSessionPrivate() :    connection (0), headerReader (0),
00056                                 headerWriter (0), bodyReader (0),
00057                                 bodyWriter (0), requestBody(), postBuffer()
00058     {}
00059 
00060 private:
00061     REFERENCE_OBJECT (ClientSessionPrivate)
00062 };
00063 
00064 } // namespace Http;
00065 
00066 ClientSession::ClientSession (Connection *connection)
00067  :  p (new ClientSessionPrivate)
00068 {
00069     p->connection   = connection;
00070     p->headerReader = new HeaderReader (connection);
00071     p->headerWriter = new HeaderWriter (connection);
00072     p->bodyReader   = new BodyReader (connection);
00073     p->bodyWriter   = new BodyWriter (connection);
00074 
00075     connect (p->headerWriter, SIGNAL (headerWritten()),
00076              this, SLOT (writeRequestBody()));
00077     connect (p->bodyWriter, SIGNAL (bodyWritten()),
00078              this, SLOT (startReadingResponse()));
00079     connect (p->headerReader, SIGNAL (headerRead()),
00080              this, SIGNAL (responseHeaderRead()));
00081     connect (p->bodyReader, SIGNAL (bodyRead()),
00082              this, SIGNAL (responseBodyRead()));
00083     // \todo Connect the error signals to something!
00084 }
00085 
00086 ClientSession::~ClientSession()
00087 {
00088     p->headerReader->disconnect (this);
00089     p->headerWriter->disconnect (this);
00090     p->bodyReader->disconnect (this);
00091     p->bodyWriter->disconnect (this);
00092 
00093     delete p->headerReader;
00094     delete p->headerWriter;
00095     delete p->bodyReader;
00096     delete p->bodyWriter;
00097     delete p;
00098 }
00099 
00100 void ClientSession::get (const QUrl &url, const Header &header)
00101 {
00102     sendRequest ("GET", url ,header, QByteArray());
00103 }
00104 
00105 void ClientSession::head (const QUrl &url, const Header &header)
00106 {
00107     sendRequest ("HEAD", url ,header, QByteArray());
00108 }
00109 
00110 void ClientSession::post (const QUrl &url, const Header &header,
00111                           const QByteArray &requestBody)
00112 {
00113     sendRequest ("POST", url, header, requestBody);
00114 }
00115 
00116 inline void ClientSession::sendRequest (const QString &method,
00117                                         const QUrl &url,
00118                                         const Header &header,
00119                                         const QByteArray &requestBody)
00120 {
00121     Q_ASSERT (p->headerWriter->canWrite());
00122 
00123     QString path = url.toEncoded (QUrl::RemoveScheme | QUrl::RemoveAuthority |
00124                                   QUrl::RemoveFragment);
00125     RequestHeader request (method, path, MajorVersion, MinorVersion);
00126     request.Header::operator= (header);
00127     request.setFieldValue ("Host", url.host());
00128 
00129     qDebug() << request.toString();
00130     p->requestBody = requestBody;
00131     p->headerWriter->write (request);
00132 }
00133 
00134 void ClientSession::writeRequestBody()
00135 {
00136     qDebug() << "starting writing request body...";
00137     if (p->requestBody.length() > 0) {
00138         p->postBuffer.setBuffer (&p->requestBody);
00139         p->bodyWriter->write (&p->postBuffer, p->requestBody.length());
00140     } else {
00141         startReadingResponse();
00142     }
00143 }
00144 
00145 void ClientSession::startReadingResponse()
00146 {
00147     qDebug() << "starting reading response header...";
00148     p->headerReader->startReading (new ResponseHeader);
00149 }
00150 
00151 const ResponseHeader * ClientSession::responseHeader() const
00152 {
00153     return dynamic_cast <const ResponseHeader *>  (p->headerReader->header());
00154 }
00155 
00156 void ClientSession::readResponseBody (QIODevice *file)
00157 {
00158     qint64 length = 0;
00159     // \todo Id no Content-Length field is given, try Transfer-Encoding: chunked
00160     // or read until connectio gets closed (HTTP/1.0 behavior)
00161     length = responseHeader()->fieldValue ("Content-Length").toLongLong();
00162     qDebug() << "starting reading response body of size" << length;
00163     p->bodyReader->startReading (file, length);
00164 }