KDECore
khttpproxysocketdevice.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026
00027 #include <sys/types.h>
00028 #include <sys/socket.h>
00029
00030 #include <qsocketnotifier.h>
00031 #include <qcstring.h>
00032
00033 #include "kresolver.h"
00034 #include "ksocketaddress.h"
00035 #include "ksocketdevice.h"
00036 #include "khttpproxysocketdevice.h"
00037
00038 using namespace KNetwork;
00039
00040 KResolverEntry KHttpProxySocketDevice::defaultProxy;
00041
00042 class KNetwork::KHttpProxySocketDevicePrivate
00043 {
00044 public:
00045 KResolverEntry proxy;
00046 QCString request;
00047 QCString reply;
00048 KSocketAddress peer;
00049
00050 KHttpProxySocketDevicePrivate()
00051 : proxy(KHttpProxySocketDevice::defaultProxy)
00052 { }
00053 };
00054
00055 KHttpProxySocketDevice::KHttpProxySocketDevice(const KSocketBase* parent)
00056 : KSocketDevice(parent), d(new KHttpProxySocketDevicePrivate)
00057 {
00058 }
00059
00060 KHttpProxySocketDevice::KHttpProxySocketDevice(const KResolverEntry& proxy)
00061 : d(new KHttpProxySocketDevicePrivate)
00062 {
00063 d->proxy = proxy;
00064 }
00065
00066 KHttpProxySocketDevice::~KHttpProxySocketDevice()
00067 {
00068
00069
00070
00071 delete d;
00072 }
00073
00074 int KHttpProxySocketDevice::capabilities() const
00075 {
00076 return CanConnectString | CanNotBind | CanNotListen | CanNotUseDatagrams;
00077 }
00078
00079 const KResolverEntry&
00080 KHttpProxySocketDevice::proxyServer() const
00081 {
00082 return d->proxy;
00083 }
00084
00085 void KHttpProxySocketDevice::setProxyServer(const KResolverEntry& proxy)
00086 {
00087 d->proxy = proxy;
00088 }
00089
00090 void KHttpProxySocketDevice::close()
00091 {
00092 d->reply = d->request = QCString();
00093 d->peer = KSocketAddress();
00094 KSocketDevice::close();
00095 }
00096
00097 KSocketAddress KHttpProxySocketDevice::peerAddress() const
00098 {
00099 if (isOpen())
00100 return d->peer;
00101 return KSocketAddress();
00102 }
00103
00104 KSocketAddress KHttpProxySocketDevice::externalAddress() const
00105 {
00106 return KSocketAddress();
00107 }
00108
00109 bool KHttpProxySocketDevice::connect(const KResolverEntry& address)
00110 {
00111 if (d->proxy.family() == AF_UNSPEC)
00112
00113 return KSocketDevice::connect(address);
00114
00115 if (isOpen())
00116 {
00117
00118 resetError();
00119 return true;
00120 }
00121
00122 if (m_sockfd == -1)
00123
00124 return connect(address.address().nodeName(),
00125 address.address().serviceName());
00126
00127 d->peer = address.address();
00128 return parseServerReply();
00129 }
00130
00131 bool KHttpProxySocketDevice::connect(const QString& node, const QString& service)
00132 {
00133
00134 if (m_sockfd == -1 && (d->proxy.family() == AF_UNSPEC ||
00135 node.isEmpty() || service.isEmpty()))
00136 {
00137
00138 setError(IO_ConnectError, NotSupported);
00139 return false;
00140 }
00141
00142 if (isOpen())
00143 {
00144
00145 return true;
00146 }
00147
00148 if (m_sockfd == -1)
00149 {
00150
00151 if (!KSocketDevice::connect(d->proxy))
00152 return false;
00153 setState(0);
00154
00155
00156 QString request = QString::fromLatin1("CONNECT %1:%2 HTTP/1.1\r\n"
00157 "Cache-Control: no-cache\r\n"
00158 "Host: \r\n"
00159 "\r\n");
00160 QString node2 = node;
00161 if (node.contains(':'))
00162 node2 = '[' + node + ']';
00163
00164 d->request = request.arg(node2).arg(service).latin1();
00165 }
00166
00167 return parseServerReply();
00168 }
00169
00170 bool KHttpProxySocketDevice::parseServerReply()
00171 {
00172
00173 if (!KSocketDevice::connect(d->proxy))
00174 if (error() == InProgress)
00175 return true;
00176 else if (error() != NoError)
00177 return false;
00178
00179 if (!d->request.isEmpty())
00180 {
00181
00182 Q_LONG written = writeBlock(d->request, d->request.length());
00183 if (written < 0)
00184 {
00185 qDebug("KHttpProxySocketDevice: would block writing request!");
00186 if (error() == WouldBlock)
00187 setError(IO_ConnectError, InProgress);
00188 return error() == WouldBlock;
00189 }
00190 qDebug("KHttpProxySocketDevice: request written");
00191
00192 d->request.remove(0, written);
00193
00194 if (!d->request.isEmpty())
00195 {
00196 setError(IO_ConnectError, InProgress);
00197 return true;
00198 }
00199 }
00200
00201
00202
00203
00204
00205 int index;
00206 if (!blocking())
00207 {
00208 Q_LONG avail = bytesAvailable();
00209 qDebug("KHttpProxySocketDevice: %ld bytes available", avail);
00210 setState(0);
00211 if (avail == 0)
00212 {
00213 setError(IO_ConnectError, InProgress);
00214 return true;
00215 }
00216 else if (avail < 0)
00217 return false;
00218
00219 QByteArray buf(avail);
00220 if (peekBlock(buf.data(), avail) < 0)
00221 return false;
00222
00223 QCString fullHeaders = d->reply + buf.data();
00224
00225 index = fullHeaders.find("\r\n\r\n");
00226 if (index == -1)
00227 {
00228
00229
00230 readBlock(buf.data(), avail);
00231 d->reply += buf.data();
00232 setError(IO_ConnectError, InProgress);
00233 return true;
00234 }
00235
00236
00237 index -= d->reply.length();
00238 d->reply += fullHeaders.mid(d->reply.length(), index + 4);
00239
00240
00241 readBlock(buf.data(), index + 4);
00242 }
00243 else
00244 {
00245 int state = 0;
00246 if (d->reply.right(3) == "\r\n\r")
00247 state = 3;
00248 else if (d->reply.right(2) == "\r\n")
00249 state = 2;
00250 else if (d->reply.right(1) == "\r")
00251 state = 1;
00252 while (state != 4)
00253 {
00254 char c = getch();
00255 d->reply += c;
00256
00257 if ((state == 3 && c == '\n') ||
00258 (state == 1 && c == '\n') ||
00259 c == '\r')
00260 ++state;
00261 else
00262 state = 0;
00263 }
00264 }
00265
00266
00267 qDebug("KHttpProxySocketDevice: get reply: %s\n",
00268 d->reply.left(d->reply.find('\r')).data());
00269 if (d->reply.left(7) != "HTTP/1." ||
00270 (index = d->reply.find(' ')) == -1 ||
00271 d->reply[index + 1] != '2')
00272 {
00273 setError(IO_ConnectError, NetFailure);
00274 return false;
00275 }
00276
00277
00278 resetError();
00279 setState(IO_Open);
00280 return true;
00281 }