khttpproxysocketdevice.cpp
00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net> 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 <config.h> 00026 00027 #include <sys/types.h> 00028 #include <sys/socket.h> 00029 00030 #include <tqsocketnotifier.h> 00031 #include <tqcstring.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 TQCString request; 00047 TQCString 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 // nothing special to be done during closing 00069 // KSocketDevice::~KSocketDevice closes the socket 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 = TQCString(); 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 // no proxy server set ! 00113 return KSocketDevice::connect(address); 00114 00115 if (isOpen()) 00116 { 00117 // socket is already open 00118 resetError(); 00119 return true; 00120 } 00121 00122 if (m_sockfd == -1) 00123 // socket isn't created yet 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 TQString& node, const TQString& service) 00132 { 00133 // same safety checks as above 00134 if (m_sockfd == -1 && (d->proxy.family() == AF_UNSPEC || 00135 node.isEmpty() || service.isEmpty())) 00136 { 00137 // no proxy server set ! 00138 setError(IO_ConnectError, NotSupported); 00139 return false; 00140 } 00141 00142 if (isOpen()) 00143 { 00144 // socket is already open 00145 return true; 00146 } 00147 00148 if (m_sockfd == -1) 00149 { 00150 // must create the socket 00151 if (!KSocketDevice::connect(d->proxy)) 00152 return false; // also unable to contact proxy server 00153 setState(0); // unset open flag 00154 00155 // prepare the request 00156 TQString request = TQString::fromLatin1("CONNECT %1:%2 HTTP/1.1\r\n" 00157 "Cache-Control: no-cache\r\n" 00158 "Host: \r\n" 00159 "\r\n"); 00160 TQString node2 = node; 00161 if (node.contains(':')) 00162 node2 = '[' + node + ']'; 00163 00164 d->request = TQString(request.arg(node2).arg(service)).latin1(); 00165 } 00166 00167 return parseServerReply(); 00168 } 00169 00170 bool KHttpProxySocketDevice::parseServerReply() 00171 { 00172 // make sure we're connected 00173 if (!KSocketDevice::connect(d->proxy)) { 00174 if (error() == InProgress) { 00175 return true; 00176 } 00177 else if (error() != NoError) { 00178 return false; 00179 } 00180 } 00181 00182 if (!d->request.isEmpty()) 00183 { 00184 // send request 00185 TQ_LONG written = tqwriteBlock(d->request, d->request.length()); 00186 if (written < 0) 00187 { 00188 qDebug("KHttpProxySocketDevice: would block writing request!"); 00189 if (error() == WouldBlock) 00190 setError(IO_ConnectError, InProgress); 00191 return error() == WouldBlock; // error 00192 } 00193 qDebug("KHttpProxySocketDevice: request written"); 00194 00195 d->request.remove(0, written); 00196 00197 if (!d->request.isEmpty()) 00198 { 00199 setError(IO_ConnectError, InProgress); 00200 return true; // still in progress 00201 } 00202 } 00203 00204 // request header is sent 00205 // must parse reply, but must also be careful not to read too much 00206 // from the buffer 00207 00208 int index; 00209 if (!blocking()) 00210 { 00211 TQ_LONG avail = bytesAvailable(); 00212 qDebug("KHttpProxySocketDevice: %ld bytes available", avail); 00213 setState(0); 00214 if (avail == 0) 00215 { 00216 setError(IO_ConnectError, InProgress); 00217 return true; 00218 } 00219 else if (avail < 0) 00220 return false; // error! 00221 00222 TQByteArray buf(avail); 00223 if (peekBlock(buf.data(), avail) < 0) 00224 return false; // error! 00225 00226 TQCString fullHeaders = d->reply + buf.data(); 00227 // search for the end of the headers 00228 index = fullHeaders.find("\r\n\r\n"); 00229 if (index == -1) 00230 { 00231 // no, headers not yet finished... 00232 // consume data from socket 00233 tqreadBlock(buf.data(), avail); 00234 d->reply += buf.data(); 00235 setError(IO_ConnectError, 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 tqreadBlock(buf.data(), index + 4); 00245 } 00246 else 00247 { 00248 int state = 0; 00249 if (d->reply.right(3) == "\r\n\r") 00250 state = 3; 00251 else if (d->reply.right(2) == "\r\n") 00252 state = 2; 00253 else if (d->reply.right(1) == "\r") 00254 state = 1; 00255 while (state != 4) 00256 { 00257 char c = getch(); 00258 d->reply += c; 00259 00260 if ((state == 3 && c == '\n') || 00261 (state == 1 && c == '\n') || 00262 c == '\r') 00263 ++state; 00264 else 00265 state = 0; 00266 } 00267 } 00268 00269 // now really parse the reply 00270 qDebug("KHttpProxySocketDevice: get reply: %s\n", 00271 d->reply.left(d->reply.find('\r')).data()); 00272 if (d->reply.left(7) != "HTTP/1." || 00273 (index = d->reply.find(' ')) == -1 || 00274 d->reply[index + 1] != '2') 00275 { 00276 setError(IO_ConnectError, NetFailure); 00277 return false; 00278 } 00279 00280 // we've got it 00281 resetError(); 00282 setState(IO_Open); 00283 return true; 00284 }