reSIProcate/repro  9694
HttpConnection.cxx
Go to the documentation of this file.
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  */