KDECore
k3httpproxysocketdevice.cpp
Go to the documentation of this file.
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 Thiago Macieira <thiago@kde.org> 00003 * 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining 00006 * a copy of this software and associated documentation files (the 00007 * "Software"), to deal in the Software without restriction, including 00008 * without limitation the rights to use, copy, modify, merge, publish, 00009 * distribute, sublicense, and/or sell copies of the Software, and to 00010 * permit persons to whom the Software is furnished to do so, subject to 00011 * the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 #include "k3httpproxysocketdevice.h" 00026 00027 #include <config.h> 00028 #include <config-network.h> 00029 00030 #include <sys/types.h> 00031 #include <sys/socket.h> 00032 00033 #include <QSocketNotifier> 00034 #include <QByteArray> 00035 00036 #include "k3resolver.h" 00037 #include "k3socketaddress.h" 00038 #include "k3socketdevice.h" 00039 00040 using namespace KNetwork; 00041 00042 KResolverEntry KHttpProxySocketDevice::defaultProxy; 00043 00044 class KNetwork::KHttpProxySocketDevicePrivate 00045 { 00046 public: 00047 KResolverEntry proxy; 00048 QByteArray request; 00049 QByteArray reply; 00050 KSocketAddress peer; 00051 00052 KHttpProxySocketDevicePrivate() 00053 : proxy(KHttpProxySocketDevice::defaultProxy) 00054 { } 00055 }; 00056 00057 KHttpProxySocketDevice::KHttpProxySocketDevice(const KSocketBase* parent) 00058 : KSocketDevice(parent), d(new KHttpProxySocketDevicePrivate) 00059 { 00060 } 00061 00062 KHttpProxySocketDevice::KHttpProxySocketDevice(const KResolverEntry& proxy) 00063 : d(new KHttpProxySocketDevicePrivate) 00064 { 00065 d->proxy = proxy; 00066 } 00067 00068 KHttpProxySocketDevice::~KHttpProxySocketDevice() 00069 { 00070 // nothing special to be done during closing 00071 // KSocketDevice::~KSocketDevice closes the socket 00072 00073 delete d; 00074 } 00075 00076 int KHttpProxySocketDevice::capabilities() const 00077 { 00078 return CanConnectString | CanNotBind | CanNotListen | CanNotUseDatagrams; 00079 } 00080 00081 const KResolverEntry& 00082 KHttpProxySocketDevice::proxyServer() const 00083 { 00084 return d->proxy; 00085 } 00086 00087 void KHttpProxySocketDevice::setProxyServer(const KResolverEntry& proxy) 00088 { 00089 d->proxy = proxy; 00090 } 00091 00092 void KHttpProxySocketDevice::close() 00093 { 00094 d->reply = d->request = QByteArray(); 00095 d->peer = KSocketAddress(); 00096 KSocketDevice::close(); 00097 } 00098 00099 KSocketAddress KHttpProxySocketDevice::peerAddress() const 00100 { 00101 if (isOpen()) 00102 return d->peer; 00103 return KSocketAddress(); 00104 } 00105 00106 KSocketAddress KHttpProxySocketDevice::externalAddress() const 00107 { 00108 return KSocketAddress(); 00109 } 00110 00111 bool KHttpProxySocketDevice::connect(const KResolverEntry& address) 00112 { 00113 if (d->proxy.family() == AF_UNSPEC) 00114 // no proxy server set ! 00115 return KSocketDevice::connect(address); 00116 00117 if (isOpen()) 00118 { 00119 // socket is already open 00120 resetError(); 00121 return true; 00122 } 00123 00124 if (m_sockfd == -1) 00125 // socket isn't created yet 00126 return connect(address.address().nodeName(), 00127 address.address().serviceName()); 00128 00129 d->peer = address.address(); 00130 return parseServerReply(); 00131 } 00132 00133 bool KHttpProxySocketDevice::connect(const QString& node, const QString& service) 00134 { 00135 // same safety checks as above 00136 if (m_sockfd == -1 && (d->proxy.family() == AF_UNSPEC || 00137 node.isEmpty() || service.isEmpty())) 00138 { 00139 // no proxy server set ! 00140 setError(NotSupported); 00141 return false; 00142 } 00143 00144 if (isOpen()) 00145 { 00146 // socket is already open 00147 return true; 00148 } 00149 00150 if (m_sockfd == -1) 00151 { 00152 // must create the socket 00153 if (!KSocketDevice::connect(d->proxy)) 00154 return false; // also unable to contact proxy server 00155 KActiveSocketBase::close(); 00156 00157 // prepare the request 00158 QString request = QLatin1String("CONNECT %1:%2 HTTP/1.1\r\n" 00159 "Cache-Control: no-cache\r\n" 00160 "Host: \r\n" 00161 "\r\n"); 00162 QString node2 = node; 00163 if (node.contains(QLatin1Char(':'))) 00164 node2 = QLatin1Char('[') + node + QLatin1Char(']'); 00165 00166 d->request = request.arg(node2).arg(service).toLatin1(); 00167 } 00168 00169 return parseServerReply(); 00170 } 00171 00172 bool KHttpProxySocketDevice::parseServerReply() 00173 { 00174 // make sure we're connected 00175 if (!KSocketDevice::connect(d->proxy)) 00176 if (error() == InProgress) 00177 return true; 00178 else if (error() != NoError) 00179 return false; 00180 00181 if (!d->request.isEmpty()) 00182 { 00183 // send request 00184 qint64 written = writeData(d->request, d->request.length()); 00185 if (written < 0) 00186 { 00187 qDebug("KHttpProxySocketDevice: would block writing request!"); 00188 if (error() == WouldBlock) 00189 setError(InProgress); 00190 return error() == WouldBlock; // error 00191 } 00192 qDebug("KHttpProxySocketDevice: request written"); 00193 00194 d->request.remove(0, written); 00195 00196 if (!d->request.isEmpty()) 00197 { 00198 setError(InProgress); 00199 return true; // still in progress 00200 } 00201 } 00202 00203 // request header is sent 00204 // must parse reply, but must also be careful not to read too much 00205 // from the buffer 00206 00207 int index; 00208 if (!blocking()) 00209 { 00210 qint64 avail = bytesAvailable(); 00211 qDebug("KHttpProxySocketDevice: %lld bytes available", avail); 00212 KActiveSocketBase::close(); 00213 if (avail == 0) 00214 { 00215 setError(InProgress); 00216 return true; 00217 } 00218 else if (avail < 0) 00219 return false; // error! 00220 00221 QByteArray buf; 00222 buf.resize(avail); 00223 if (peekData(buf.data(), avail) < 0) 00224 return false; // error! 00225 00226 QByteArray fullHeaders = d->reply + buf; 00227 // search for the end of the headers 00228 index = fullHeaders.indexOf("\r\n\r\n"); 00229 if (index == -1) 00230 { 00231 // no, headers not yet finished... 00232 // consume data from socket 00233 readData(buf.data(), avail); 00234 d->reply += buf.data(); 00235 setError(InProgress); 00236 return true; 00237 } 00238 00239 // headers are finished 00240 index -= d->reply.length(); 00241 d->reply += fullHeaders.mid(d->reply.length(), index + 4); 00242 00243 // consume from socket 00244 readData(buf.data(), index + 4); 00245 } 00246 else 00247 { 00248 int state = 0; 00249 if (d->reply.endsWith("\r\n\r")) // krazy:exclude=strings 00250 state = 3; 00251 else if (d->reply.endsWith("\r\n")) // krazy:exclude=strings 00252 state = 2; 00253 else if (d->reply.endsWith('\r'))// krazy:exclude=strings 00254 state = 1; 00255 while (state != 4) 00256 { 00257 char c; 00258 getChar(&c); 00259 d->reply += c; 00260 00261 if ((state == 3 && c == '\n') || 00262 (state == 1 && c == '\n') || 00263 c == '\r') 00264 ++state; 00265 else 00266 state = 0; 00267 } 00268 } 00269 00270 // now really parse the reply 00271 qDebug("KHttpProxySocketDevice: get reply: %s\n", 00272 d->reply.left(d->reply.indexOf('\r')).data()); 00273 if (d->reply.left(7) != "HTTP/1." || 00274 (index = d->reply.indexOf(' ')) == -1 || 00275 d->reply[index + 1] != '2') 00276 { 00277 setError(NetFailure); 00278 return false; 00279 } 00280 00281 // we've got it 00282 resetError(); 00283 KActiveSocketBase::open(ReadOnly); 00284 return true; 00285 }
KDE 4.6 API Reference