|
reSIProcate/repro
9694
|
00001 #include <cassert> 00002 00003 #include "rutil/Data.hxx" 00004 #include "rutil/Socket.hxx" 00005 #include "resip/stack/Symbols.hxx" 00006 #include "rutil/TransportType.hxx" 00007 #include "rutil/Logger.hxx" 00008 #include "resip/stack/Tuple.hxx" 00009 #include "rutil/DnsUtil.hxx" 00010 #include "rutil/ParseBuffer.hxx" 00011 00012 #include "repro/ReproVersion.hxx" 00013 #include "repro/HttpBase.hxx" 00014 #include "repro/HttpConnection.hxx" 00015 00016 00017 using namespace resip; 00018 using namespace repro; 00019 using namespace std; 00020 00021 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO 00022 00023 int HttpConnection::nextPageNumber=1; 00024 00025 00026 00027 00028 HttpConnection::HttpConnection( HttpBase& base, Socket pSock ): 00029 mHttpBase( base ), 00030 mPageNumber(nextPageNumber++), 00031 mSock(pSock), 00032 mParsedRequest(false) 00033 { 00034 assert( mSock > 0 ); 00035 } 00036 00037 00038 HttpConnection::~HttpConnection() 00039 { 00040 assert( mSock > 0 ); 00041 #ifdef WIN32 00042 closesocket(mSock); mSock=0; 00043 #else 00044 close(mSock); mSock=0; 00045 #endif 00046 } 00047 00048 00049 void 00050 HttpConnection::buildFdSet(FdSet& fdset) 00051 { 00052 if ( !mTxBuffer.empty() ) 00053 { 00054 fdset.setWrite(mSock); 00055 } 00056 fdset.setRead(mSock); 00057 } 00058 00059 00060 bool 00061 HttpConnection::process(FdSet& fdset) 00062 { 00063 if ( fdset.hasException(mSock) ) 00064 { 00065 int errNum = 0; 00066 int errNumSize = sizeof(errNum); 00067 getsockopt(mSock,SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize); 00068 InfoLog (<< "Exception reading from socket " 00069 << (int)mSock << " code: " << errNum << "; closing connection"); 00070 return false; 00071 } 00072 00073 if ( fdset.readyToRead( mSock ) ) 00074 { 00075 bool ok = processSomeReads(); 00076 if ( !ok ) 00077 { 00078 return false; 00079 } 00080 } 00081 if ( (!mTxBuffer.empty()) && fdset.readyToWrite( mSock ) ) 00082 { 00083 bool ok = processSomeWrites(); 00084 if ( !ok ) 00085 { 00086 return false; 00087 } 00088 } 00089 00090 return true; 00091 } 00092 00093 00094 void 00095 HttpConnection::setPage(const Data& pPage,int response,const Mime& pType) 00096 { 00097 Data page(pPage); 00098 00099 switch (response) 00100 { 00101 case 401: 00102 { 00103 mTxBuffer += "HTTP/1.0 401 Unauthorized"; mTxBuffer += Symbols::CRLF; 00104 00105 page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">" 00106 "<html><head>" 00107 "<title>401 Unauthorized</title>" 00108 "</head><body>" 00109 "<h1>Unauthorized</h1>" 00110 "</body></html>" ); 00111 } 00112 break; 00113 00114 case 404: 00115 { 00116 mTxBuffer += "HTTP/1.0 404 Not Found"; mTxBuffer += Symbols::CRLF; 00117 00118 page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">" 00119 "<html><head>" 00120 "<title>404 Not Found</title>" 00121 "</head><body>" 00122 "<h1>Unauthorized</h1>" 00123 "</body></html>" ); 00124 } 00125 break; 00126 00127 case 301: 00128 { 00129 mTxBuffer += "HTTP/1.0 301 Moved Permanently"; mTxBuffer += Symbols::CRLF; 00130 mTxBuffer += "Location: http:/index.html"; mTxBuffer += Symbols::CRLF; 00131 00132 page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">" 00133 "<html><head>" 00134 "<title>301 Moved Permanently</title>" 00135 "</head><body>" 00136 "<h1>Moved</h1>" 00137 "</body></html>" ); 00138 } 00139 break; 00140 00141 case 200: 00142 { 00143 mTxBuffer += "HTTP/1.0 200 OK" ; mTxBuffer += Symbols::CRLF; 00144 } 00145 break; 00146 00147 default: 00148 { 00149 assert(0); 00150 00151 Data resp; 00152 { 00153 DataStream s(resp); 00154 s << response; 00155 s.flush(); 00156 } 00157 00158 mTxBuffer += "HTTP/1.0 "; 00159 mTxBuffer += resp; 00160 mTxBuffer += "OK" ; mTxBuffer += Symbols::CRLF; 00161 } 00162 break; 00163 } 00164 00165 Data len; 00166 { 00167 DataStream s(len); 00168 s << page.size(); 00169 s.flush(); 00170 } 00171 00172 mTxBuffer += "WWW-Authenticate: Basic realm=\""; 00173 if ( mHttpBase.mRealm.empty() ) 00174 { 00175 mTxBuffer += resip::DnsUtil::getLocalHostName(); 00176 } 00177 else 00178 { 00179 mTxBuffer += mHttpBase.mRealm; 00180 } 00181 mTxBuffer += "\" "; 00182 mTxBuffer += Symbols::CRLF; 00183 00184 mTxBuffer += "Server: Repro Proxy " ; 00185 mTxBuffer += Data(VersionUtils::instance().displayVersion()); 00186 mTxBuffer += Symbols::CRLF; 00187 mTxBuffer += "Mime-version: 1.0 " ; mTxBuffer += Symbols::CRLF; 00188 mTxBuffer += "Pragma: no-cache " ; mTxBuffer += Symbols::CRLF; 00189 mTxBuffer += "Content-Length: "; mTxBuffer += len; mTxBuffer += Symbols::CRLF; 00190 00191 mTxBuffer += "Content-Type: " ; 00192 mTxBuffer += pType.type() ; 00193 mTxBuffer +="/" ; 00194 mTxBuffer += pType.subType() ; mTxBuffer += Symbols::CRLF; 00195 00196 mTxBuffer += Symbols::CRLF; 00197 00198 mTxBuffer += page; 00199 } 00200 00201 00202 bool 00203 HttpConnection::processSomeReads() 00204 { 00205 const int bufSize = 8000; 00206 char buf[bufSize]; 00207 00208 00209 #if defined(WIN32) 00210 int bytesRead = ::recv(mSock, buf, bufSize, 0); 00211 #else 00212 int bytesRead = ::read(mSock, buf, bufSize); 00213 #endif 00214 00215 if (bytesRead == INVALID_SOCKET) 00216 { 00217 int e = getErrno(); 00218 switch (e) 00219 { 00220 case EAGAIN: 00221 InfoLog (<< "No data ready to read"); 00222 return true; 00223 case EINTR: 00224 InfoLog (<< "The call was interrupted by a signal before any data was read."); 00225 break; 00226 case EIO: 00227 InfoLog (<< "I/O error"); 00228 break; 00229 case EBADF: 00230 InfoLog (<< "fd is not a valid file descriptor or is not open for reading."); 00231 break; 00232 case EINVAL: 00233 InfoLog (<< "fd is attached to an object which is unsuitable for reading."); 00234 break; 00235 case EFAULT: 00236 InfoLog (<< "buf is outside your accessible address space."); 00237 break; 00238 default: 00239 InfoLog (<< "Some other error"); 00240 break; 00241 } 00242 InfoLog (<< "Failed read on " << (int)mSock << " " << strerror(e)); 00243 return false; 00244 } 00245 else if (bytesRead == 0) 00246 { 00247 InfoLog (<< "Connection closed by remote " ); 00248 return false; 00249 } 00250 00251 //DebugLog (<< "HttpConnection::processSomeReads() " 00252 // << " read=" << bytesRead); 00253 00254 mRxBuffer += Data( buf, bytesRead ); 00255 00256 tryParse(); 00257 00258 return true; 00259 } 00260 00261 00262 void 00263 HttpConnection::tryParse() 00264 { 00265 //DebugLog (<< "parse " << mRxBuffer ); 00266 00267 ParseBuffer pb(mRxBuffer); 00268 00269 // See if we have the entire message 00270 pb.skipToChars(Symbols::CRLFCRLF); 00271 if(pb.eof()) 00272 { 00273 // End of message not found - keep reading 00274 return; 00275 } 00276 pb.reset(pb.start()); 00277 00278 pb.skipToChar(Symbols::SPACE[0]); 00279 const char* start = pb.skipWhitespace(); 00280 pb.skipToChar(Symbols::SPACE[0]); 00281 00282 if (pb.eof()) 00283 { 00284 // parse failed - just return 00285 return; 00286 } 00287 00288 Data uri; 00289 pb.data( uri, start ); 00290 00291 DebugLog (<< "parse found URI " << uri ); 00292 mParsedRequest = true; 00293 00294 00295 Data user; 00296 Data password; 00297 00298 try 00299 { 00300 pb.skipToChars("Authorization"); 00301 if (!pb.eof()) 00302 { 00303 if ( pb.eof() ) DebugLog( << "Did not find Authorization header" ); 00304 pb.skipToChars( "Basic" ); pb.skipN(6); 00305 if ( pb.eof() ) DebugLog( << "Did not find Authorization basic " ); 00306 pb.skipWhitespace(); 00307 if ( pb.eof() ) DebugLog( << "Something weird in Auhtorization header " ); 00308 if ( !pb.eof() ) 00309 { 00310 const char* a = pb.position(); 00311 pb.skipNonWhitespace(); 00312 Data buf = pb.data(a); 00313 00314 DebugLog (<< "parse found basic base64 auth data of " << buf ); 00315 Data auth = buf.base64decode(); 00316 00317 //DebugLog (<< "parse found basic auth data of " << auth ); 00318 00319 ParseBuffer p(auth); 00320 const char* a1 = p.position(); 00321 p.skipToChar(':'); 00322 user = p.data(a1); 00323 const char* a2 = p.skipChar(':'); 00324 p.skipToEnd(); 00325 password = p.data(a2); 00326 00327 //DebugLog (<< "parse found basic auth data with user=" << user 00328 // << " password=" << password ); 00329 } 00330 } 00331 } 00332 catch ( ... ) 00333 { 00334 ErrLog (<< "Some problem finding Authorization header in HTTP request" ); 00335 } 00336 00337 mHttpBase.buildPage(uri,mPageNumber,user,password); 00338 } 00339 00340 00341 bool 00342 HttpConnection::processSomeWrites() 00343 { 00344 if ( mTxBuffer.empty() ) 00345 { 00346 return true; 00347 } 00348 00349 //DebugLog (<< "Writing " << mTxBuffer ); 00350 00351 #if defined(WIN32) 00352 int bytesWritten = ::send( mSock, mTxBuffer.data(), (int)mTxBuffer.size(), 0); 00353 #else 00354 int bytesWritten = ::write(mSock, mTxBuffer.data(), (int)mTxBuffer.size() ); 00355 #endif 00356 00357 if (bytesWritten == INVALID_SOCKET) 00358 { 00359 int e = getErrno(); 00360 InfoLog (<< "HttpConnection failed write on " << mSock << " " << strerror(e)); 00361 00362 return false; 00363 } 00364 00365 if (bytesWritten == (int)mTxBuffer.size() ) 00366 { 00367 DebugLog (<< "Wrote it all" ); 00368 mTxBuffer = Data::Empty; 00369 00370 return false; // return false causes connection to close and clean up 00371 } 00372 else 00373 { 00374 Data rest = mTxBuffer.substr(bytesWritten); 00375 mTxBuffer = rest; 00376 DebugLog( << "Wrote " << bytesWritten << " bytes - still need to do " << mTxBuffer ); 00377 } 00378 00379 return true; 00380 } 00381 00382 00383 /* ==================================================================== 00384 * The Vovida Software License, Version 1.0 00385 * 00386 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00387 * 00388 * Redistribution and use in source and binary forms, with or without 00389 * modification, are permitted provided that the following conditions 00390 * are met: 00391 * 00392 * 1. Redistributions of source code must retain the above copyright 00393 * notice, this list of conditions and the following disclaimer. 00394 * 00395 * 2. Redistributions in binary form must reproduce the above copyright 00396 * notice, this list of conditions and the following disclaimer in 00397 * the documentation and/or other materials provided with the 00398 * distribution. 00399 * 00400 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00401 * and "Vovida Open Communication Application Library (VOCAL)" must 00402 * not be used to endorse or promote products derived from this 00403 * software without prior written permission. For written 00404 * permission, please contact vocal@vovida.org. 00405 * 00406 * 4. Products derived from this software may not be called "VOCAL", nor 00407 * may "VOCAL" appear in their name, without prior written 00408 * permission of Vovida Networks, Inc. 00409 * 00410 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00411 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00412 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00413 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00414 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00415 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00416 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00417 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00418 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00419 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00420 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00421 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00422 * DAMAGE. 00423 * 00424 * ==================================================================== 00425 * 00426 * This software consists of voluntary contributions made by Vovida 00427 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00428 * Inc. For more information on Vovida Networks, Inc., please see 00429 * <http://www.vovida.org/>. 00430 * 00431 */
1.7.5.1