Back to index

lightning-sunbird  0.9+nobinonly
nsHTTPConn.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <assert.h>
00044 #include <sys/stat.h>
00045 #include "nsHTTPConn.h"
00046 #include "nsSocket.h"
00047 
00048 const char kHTTPProto[8] = "http://";
00049 const char kFTPProto[8] = "ftp://";
00050 const int kHTTPPort = 80;
00051 const int kFTPPort = 21;
00052 const int kRespBufSize = 1024;
00053 const int kReqBufSize = 4096;
00054 const int kHdrBufSize = 4096;
00055 const char kCRLF[3] = "\r\n";
00056 const char kHdrBodyDelim[5] = "\r\n\r\n";
00057 const char kDefaultDestFile[11] = "index.html";
00058 
00059 nsHTTPConn::nsHTTPConn(char *aHost, int aPort, char *aPath, int (*aEventPumpCB)(void)): 
00060     mEventPumpCB(aEventPumpCB),
00061     mHost(aHost),
00062     mPath(aPath),
00063     mProxiedURL(NULL),
00064     mProxyUser(NULL),
00065     mProxyPswd(NULL),
00066     mDestFile(NULL),
00067     mHostPathAllocd(FALSE),
00068     mSocket(NULL)
00069 {
00070     if (aPort <= 0)
00071         mPort = kHTTPPort;
00072     else
00073         mPort = aPort;
00074 
00075     DUMP(("mHost = %s\n", mHost));
00076     DUMP(("mPort = %d\n", mPort));
00077     DUMP(("mPath = %s\n", mPath));
00078 }
00079 
00080 nsHTTPConn::nsHTTPConn(char *aHost, int aPort, char *aPath) :
00081     mEventPumpCB(NULL),
00082     mHost(aHost),
00083     mPath(aPath),
00084     mProxiedURL(NULL),
00085     mProxyUser(NULL),
00086     mProxyPswd(NULL),
00087     mDestFile(NULL),
00088     mHostPathAllocd(FALSE),
00089     mSocket(NULL)
00090 {
00091     if (aPort <= 0)
00092         mPort = kHTTPPort;
00093     else
00094         mPort = aPort;
00095 
00096     DUMP(("mHost = %s\n", mHost));
00097     DUMP(("mPort = %d\n", mPort));
00098     DUMP(("mPath = %s\n", mPath));
00099 }
00100 
00101 nsHTTPConn::nsHTTPConn(char *aURL, int (*aEventPumpCB)(void)) :
00102     mEventPumpCB(aEventPumpCB),
00103     mPort(kHTTPPort),
00104     mProxiedURL(NULL),
00105     mProxyUser(NULL),
00106     mProxyPswd(NULL),
00107     mDestFile(NULL),
00108     mHostPathAllocd(FALSE),
00109     mSocket(NULL),
00110     mResponseCode(0)
00111 {
00112     // parse URL
00113     if (ParseURL(kHTTPProto, aURL, &mHost, &mPort, &mPath) == OK)
00114         mHostPathAllocd = TRUE;
00115     else
00116     {
00117         mHost = NULL;
00118         mPath = NULL;
00119     }
00120 
00121     DUMP(("mHost = %s\n", mHost));
00122     DUMP(("mPort = %d\n", mPort));
00123     DUMP(("mPath = %s\n", mPath));
00124 }
00125 
00126 nsHTTPConn::nsHTTPConn(char *aURL) :
00127     mEventPumpCB(NULL),
00128     mPort(kHTTPPort),
00129     mProxiedURL(NULL),
00130     mProxyUser(NULL),
00131     mProxyPswd(NULL),
00132     mDestFile(NULL),
00133     mHostPathAllocd(FALSE),
00134     mSocket(NULL),
00135     mResponseCode(0)
00136 {
00137     // parse URL
00138     if (ParseURL(kHTTPProto, aURL, &mHost, &mPort, &mPath) == OK)
00139         mHostPathAllocd = TRUE;
00140     else
00141     {
00142         mHost = NULL;
00143         mPath = NULL;
00144     }
00145 
00146     DUMP(("mHost = %s\n", mHost));
00147     DUMP(("mPort = %d\n", mPort));
00148     DUMP(("mPath = %s\n", mPath));
00149 }
00150 
00151 nsHTTPConn::~nsHTTPConn()
00152 {
00153     if (mHostPathAllocd)
00154     {
00155         if (mHost)
00156             free(mHost);
00157         if (mPath)
00158             free(mPath);
00159     }
00160 }
00161     
00162 int
00163 nsHTTPConn::Open()
00164 {
00165     // verify host && path
00166     if (!mHost || !mPath)
00167         return E_MALFORMED_URL;
00168 
00169     // create socket
00170     mSocket = new nsSocket(mHost, mPort, mEventPumpCB);
00171     if (!mSocket)
00172         return E_MEM;
00173 
00174     // open socket
00175     return mSocket->Open();
00176 }
00177 
00178 int
00179 nsHTTPConn::ResumeOrGet(HTTPGetCB aCallback, char *aDestFile)
00180 {
00181     struct stat stbuf;
00182     int rv = 0;
00183     int resPos = 0;
00184     
00185     if (!aDestFile)
00186         return E_PARAM;
00187 
00188     /* stat local file */
00189     rv = stat(aDestFile, &stbuf);
00190     if (rv == 0)
00191         resPos = stbuf.st_size;
00192 
00193     return Get(aCallback, aDestFile, resPos);
00194 
00195     // XXX TO DO:
00196     // XXX handle proxies
00197 }
00198 
00199 int 
00200 nsHTTPConn::Get(HTTPGetCB aCallback, char *aDestFile)
00201 {
00202     // deprecated API; wrapper for backwards compatibility
00203 
00204     return ResumeOrGet(aCallback, aDestFile);
00205 }
00206 
00207 int
00208 nsHTTPConn::Get(HTTPGetCB aCallback, char *aDestFile, int aResumePos)
00209 {
00210     int rv;
00211     char *pathToUse;
00212 
00213     // verify host && path
00214     if (!mHost || !mPath)
00215         return E_MALFORMED_URL;
00216 
00217     if (!aDestFile)
00218     {
00219         if (mProxiedURL)
00220             pathToUse = mProxiedURL;
00221         else
00222             pathToUse = mPath;
00223 
00224         // no leaf: assume default file 'index.html'
00225         if (*(pathToUse + strlen(pathToUse) - 1) == '/')
00226             aDestFile = (char *) kDefaultDestFile;
00227         else
00228             aDestFile = strrchr(pathToUse, '/') + 1;
00229     }
00230 
00231     // issue request
00232     rv = Request(aResumePos);
00233 
00234     // recv response
00235     if (rv == OK)
00236         rv = Response(aCallback, aDestFile, aResumePos);
00237 
00238     return rv;
00239 }
00240 
00241 int
00242 nsHTTPConn::Close()
00243 {
00244     int rv;
00245 
00246     // close socket
00247     rv = mSocket->Close();
00248 
00249     // destroy socket
00250     delete mSocket;
00251 
00252     return rv;
00253 }
00254 
00255 void
00256 nsHTTPConn::SetProxyInfo(char *aProxiedURL, char *aProxyUser, 
00257                                             char *aProxyPswd)
00258 {
00259     mProxiedURL = aProxiedURL;
00260     mProxyUser = aProxyUser;
00261     mProxyPswd = aProxyPswd;
00262 }
00263 
00264 int
00265 nsHTTPConn::Request(int aResumePos)
00266 {
00267     char req[kReqBufSize];
00268     char hdr[kHdrBufSize];
00269     int rv;
00270 
00271     memset(req, 0, kReqBufSize);
00272 
00273     // format header buf:
00274 
00275     // request line
00276     memset(hdr, 0, kHdrBufSize);
00277     if (mProxiedURL)
00278     {
00279         char *host = NULL, *path = NULL;
00280         char proto[8];
00281         int port;
00282 #ifdef DEBUG
00283         assert(sizeof hdr > (strlen(mProxiedURL) + 15 ));
00284 #endif
00285         sprintf(hdr, "GET %s HTTP/1.0%s", mProxiedURL, kCRLF);
00286         strcpy(req, hdr);
00287         if (strncmp(mProxiedURL, kFTPProto, strlen(kFTPProto)) == 0) 
00288         {
00289             strcpy(proto,kFTPProto);
00290             port = kFTPPort;
00291         } 
00292         else 
00293         {
00294             strcpy(proto,kHTTPProto);
00295             port = kHTTPPort;
00296         }
00297         rv = ParseURL(proto, mProxiedURL,
00298                       &host, &port, &path);
00299         if (rv == OK) {
00300             memset(hdr, 0, kHdrBufSize);
00301             sprintf(hdr, "Host: %s:%d%s", host, port, kCRLF);
00302             strcat(req, hdr);
00303         }
00304         if (host)
00305             free(host);
00306         if (path)
00307             free(path);
00308     }
00309     else
00310     {
00311         sprintf(hdr, "GET %s HTTP/1.0%s", mPath, kCRLF);
00312         strcpy(req, hdr);
00313 
00314         memset(hdr, 0, kHdrBufSize);
00315         sprintf(hdr, "Host: %s%s", mHost, kCRLF);
00316         strcat(req, hdr);
00317     }
00318 
00319     // if proxy set and proxy user/pswd set
00320     if (mProxyUser && mProxyPswd)
00321     {
00322         char *usrPsd = (char *) malloc(strlen(mProxyUser) +
00323                                        strlen(":")        +
00324                                        strlen(mProxyPswd) + 1);
00325         if (!usrPsd)
00326             return E_MEM;
00327         sprintf(usrPsd, "%s:%s", mProxyUser, mProxyPswd);
00328 
00329         // base 64 encode proxy header
00330         char usrPsdEncoded[128];  // pray that 128 is long enough 
00331         memset(usrPsdEncoded, 0, 128);
00332 
00333         DUMP(("Unencoded string: %s\n", usrPsd));
00334         rv = Base64Encode((const unsigned char *)usrPsd, strlen(usrPsd),
00335                           usrPsdEncoded, 128);
00336         DUMP(("Encoded string: %s\n", usrPsdEncoded));
00337         DUMP(("Base64Encode returned: %d\n", rv));
00338         if (rv <= 0)
00339         {
00340             return E_B64_ENCODE;
00341         }
00342 
00343         // append proxy header to header buf
00344         memset(hdr, 0, kHdrBufSize);
00345         sprintf(hdr, "Proxy-authorization: Basic %s%s", usrPsdEncoded, kCRLF);
00346         strcat(req, hdr);
00347 
00348         // XXX append host with port 21 if ftp
00349         
00350     }
00351 
00352     // byte range support
00353     if (aResumePos > 0)
00354     {
00355         sprintf(hdr, "Range: bytes=%d-%s", aResumePos, kCRLF);
00356         strcat(req, hdr);
00357     }
00358 
00359     // headers all done so indicate
00360     strcat(req, kCRLF);
00361 
00362     // send header buf over socket
00363     int bufSize = strlen(req);
00364     rv = mSocket->Send((unsigned char *) req, &bufSize);
00365     DUMP(("\n\n%s", req));
00366 
00367     if (bufSize != (int) strlen(req))
00368         rv = E_REQ_INCOMPLETE;
00369 
00370     return rv;
00371 }
00372 
00373 int 
00374 nsHTTPConn::Response(HTTPGetCB aCallback, char *aDestFile, int aResumePos)
00375 {
00376     // NOTE: overwrites dest file if it already exists
00377 
00378     int rv = OK;
00379     char resp[kRespBufSize];
00380     int bufSize, total = 0, fwriteLen, fwrote, bytesWritten = 0, expectedSize = 0;
00381     FILE *destFd;
00382     char *fwritePos;
00383     int bFirstIter = TRUE;
00384 
00385     if (!aDestFile)
00386         return E_PARAM;
00387 
00388     // open dest file 
00389     if (aResumePos > 0)
00390     {
00391         destFd = fopen(aDestFile, "r+b");
00392         if (!destFd)
00393             return E_OPEN_FILE;
00394 
00395         if (fseek(destFd, aResumePos, SEEK_SET) != 0)
00396         {
00397             fclose(destFd);
00398             return E_SEEK_FILE;
00399         }
00400     }
00401     else
00402     {
00403         destFd = fopen(aDestFile, "w+b");
00404         if (!destFd)
00405             return E_OPEN_FILE;
00406     }
00407 
00408     // iteratively recv response 
00409     do
00410     {
00411         memset(resp, 0, kRespBufSize);
00412         bufSize = kRespBufSize;       
00413         
00414         rv = mSocket->Recv((unsigned char *) resp, &bufSize);
00415         DUMP(("nsSocket::Recv returned: %d\t and recd: %d\n", rv, bufSize));
00416 
00417         if(rv == nsSocket::E_EOF_FOUND || (rv != nsSocket::E_READ_MORE && rv != nsSocket::OK) ) {
00418             break;
00419         }
00420 
00421         if (bFirstIter)
00422         {
00423             fwritePos = strstr(resp, kHdrBodyDelim);
00424             if (fwritePos == NULL)
00425             {
00426                 // XXX  no header!  should we handle?
00427                 fwritePos = resp;
00428                 fwriteLen = bufSize;
00429             }
00430             else
00431             {
00432                 ParseResponseCode((const char *)resp, &mResponseCode);
00433                 
00434                 if ( mResponseCode < 200 || mResponseCode >=300 )
00435                 {
00436                   // if we don't get a response code in the 200 range then fail
00437                   // TODO: handle the response codes in the 300 range
00438                   rv = nsHTTPConn::E_HTTP_RESPONSE;
00439                   break;
00440                 }
00441 
00442                 ParseContentLength((const char *)resp, &expectedSize);
00443 
00444                 // move past hdr-body delimiter
00445                 fwritePos += strlen(kHdrBodyDelim);
00446                 fwriteLen = bufSize - (fwritePos - resp);
00447                 total = expectedSize + aResumePos;
00448             }
00449 
00450             bFirstIter = FALSE;
00451         }
00452         else
00453         {
00454             fwritePos = resp;
00455             fwriteLen = bufSize;
00456         }
00457 
00458         fwrote = fwrite(fwritePos, sizeof(char), fwriteLen, destFd);
00459         assert(fwrote == fwriteLen);
00460 
00461         if (fwriteLen > 0)
00462             bytesWritten += fwriteLen;
00463         if (aCallback && 
00464            (aCallback(bytesWritten, total) == E_USER_CANCEL))
00465               rv = E_USER_CANCEL; // we want to ignore all errors returned
00466                                   // from aCallback() except E_USER_CANCEL 
00467 
00468         if ( mEventPumpCB )
00469             mEventPumpCB();
00470 
00471     } while ( rv == nsSocket::E_READ_MORE || rv == nsSocket::OK);
00472     
00473     if ( bytesWritten == expectedSize && rv != nsHTTPConn::E_HTTP_RESPONSE)
00474         rv = nsSocket::E_EOF_FOUND;
00475         
00476     if (rv == nsSocket::E_EOF_FOUND)
00477     {
00478         DUMP(("EOF detected\n"));
00479         rv = OK;
00480     }
00481 
00482     fclose(destFd);
00483 
00484     return rv;
00485 }
00486 
00487 int
00488 nsHTTPConn::ParseURL(const char *aProto, char *aURL, char **aHost, 
00489                      int *aPort, char **aPath)
00490 {
00491     char *pos, *nextSlash, *nextColon, *end, *hostEnd;
00492     int protoLen = strlen(aProto);
00493 
00494     if (!aURL || !aHost || !aPort || !aPath || !aProto)
00495         return E_PARAM;
00496 
00497     if ((strncmp(aURL, aProto, protoLen) != 0) ||
00498         (strlen(aURL) < 9))
00499         return E_MALFORMED_URL;
00500 
00501     pos = aURL + protoLen;
00502     nextColon = strchr(pos, ':');
00503     nextSlash = strchr(pos, '/');
00504 
00505     // optional port specification
00506     if (nextColon && ((nextSlash && nextColon < nextSlash) || 
00507                        !nextSlash))
00508     {
00509         int portStrLen;
00510         if (nextSlash)
00511             portStrLen = nextSlash - nextColon;
00512         else
00513             portStrLen = strlen(nextColon);
00514 
00515         char *portStr = (char *) malloc(portStrLen + 1);
00516         if (!portStr)
00517             return E_MEM;
00518         memset(portStr, 0, portStrLen + 1);
00519         strncpy(portStr, nextColon+1, portStrLen);
00520         *aPort = atoi(portStr);
00521         free(portStr);
00522     }
00523     if ( (!nextColon || (nextSlash && (nextColon > nextSlash)))
00524          && *aPort <= 0) // don't override port if already set
00525         *aPort = -1;
00526 
00527     // only host in URL, assume '/' for path
00528     if (!nextSlash)
00529     {
00530         int copyLen;
00531         if (nextColon)
00532             copyLen = nextColon - pos;
00533         else
00534             copyLen = strlen(pos);
00535 
00536         *aHost = (char *) malloc(copyLen + 1); // to NULL terminate
00537         if (!aHost)
00538             return E_MEM;
00539         memset(*aHost, 0, copyLen + 1);
00540         strncpy(*aHost, pos, copyLen);
00541 
00542         *aPath = (char *) malloc(2);
00543         strcpy(*aPath, "/");
00544 
00545         return OK;
00546     }
00547     
00548     // normal parsing: both host and path exist
00549     if (nextColon)
00550         hostEnd = nextColon;
00551     else
00552         hostEnd = nextSlash;
00553     *aHost = (char *) malloc(hostEnd - pos + 1); // to NULL terminate
00554     if (!*aHost)
00555         return E_MEM;
00556               memset(*aHost, 0, hostEnd - pos + 1);
00557     strncpy(*aHost, pos, hostEnd - pos);
00558     *(*aHost + (hostEnd - pos)) = 0; // NULL terminate
00559 
00560     pos = nextSlash;
00561     end = aURL + strlen(aURL);
00562 
00563     *aPath = (char *) malloc(end - pos + 1);
00564     if (!*aPath)
00565     {
00566         if (*aHost)
00567             free(*aHost);
00568         return E_MEM;
00569     }
00570     memset(*aPath, 0, end - pos + 1);
00571     strncpy(*aPath, pos, end - pos);
00572 
00573     return OK;
00574 }
00575 
00576 void
00577 nsHTTPConn::ParseResponseCode(const char *aBuf, int *aCode)
00578 {
00579   char codeStr[4];
00580   const char *pos;
00581 
00582   if (!aBuf || !aCode)
00583     return;
00584 
00585   // make sure the beginning of the buffer is the HTTP status code
00586   if (strncmp(aBuf,"HTTP/",5) == 0)
00587   {
00588     pos = strstr(aBuf," ");  // find the space before the code
00589     ++pos;                   // move to the beginning of the code
00590     strncpy((char *)codeStr,pos, 3);
00591     codeStr[3] = '\0';
00592     *aCode = atoi(codeStr);
00593   }
00594 }
00595 
00596 void
00597 nsHTTPConn::ParseContentLength(const char *aBuf, int *aLength)
00598 {
00599     const char *clHdr; // Content-length header line start
00600     const char *eol, *pos;
00601     char clNameStr1[16] = "Content-length:";
00602     char clNameStr2[16] = "Content-Length:";
00603     char *clNameStr = clNameStr1;
00604 
00605     if (!aBuf || !aLength)
00606         return;  // non fatal so no error codes returned
00607     *aLength = 0;
00608 
00609     // XXX strcasestr() needs to be ported for Solaris (and Win32 and Mac?)
00610     clHdr = strstr(aBuf, (char *)clNameStr1);
00611     if (!clHdr)
00612     {
00613         clHdr = strstr(aBuf, (char *)clNameStr2);
00614         clNameStr = clNameStr2;
00615     }
00616     if (clHdr)
00617     {
00618         eol = strstr(clHdr, kCRLF); // end of line
00619         pos = clHdr + strlen(clNameStr);
00620         while ((pos < eol) && (*pos == ' ' || *pos == '\t'))
00621             pos++;
00622         if (pos < eol)
00623         {
00624             int clValStrLen = eol - pos + 1; // extra byte to NULL terminate
00625             char *clValStr = (char *) malloc(clValStrLen);
00626             if (!clValStr)
00627                 return; // imminent doom!
00628 
00629             memset(clValStr, 0, clValStrLen);
00630             strncpy(clValStr, pos, eol - pos);
00631             *aLength = atoi(clValStr);
00632         }
00633     } 
00634 }
00635 
00636 int 
00637 nsHTTPConn::Base64Encode(const unsigned char *in_str, int in_len, 
00638                          char *out_str, int out_len)
00639 {
00640     // NOTE: shamelessly copied from nsAbSyncPostEngine.cpp
00641 
00642     static unsigned char base64[] =
00643     {  
00644       /* 0    1    2    3    4    5    6    7        */ 
00645         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */
00646         'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ 
00647         'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ 
00648         'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ 
00649         'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ 
00650         'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ 
00651         'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */
00652         '4', '5', '6', '7', '8', '9', '+', '/'  /* 7 */ 
00653     };
00654 
00655     int curr_out_len = 0;
00656 
00657     int i = 0;
00658     unsigned char a, b, c;
00659 
00660     out_str[0] = '\0';
00661     
00662     if (in_len > 0)
00663     {
00664 
00665         while (i < in_len)
00666         {
00667             a = in_str[i];
00668             b = (i + 1 >= in_len) ? 0 : in_str[i + 1];
00669             c = (i + 2 >= in_len) ? 0 : in_str[i + 2];
00670 
00671             if (i + 2 < in_len)
00672             {
00673                 out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]);
00674                 out_str[curr_out_len++] = (base64[((a << 4) & 0x30)
00675                                             + ((b >> 4) & 0xf)]);
00676                 out_str[curr_out_len++] = (base64[((b << 2) & 0x3c)
00677                                             + ((c >> 6) & 0x3)]);
00678                 out_str[curr_out_len++] = (base64[c & 0x3F]);
00679             }
00680             else if (i + 1 < in_len)
00681             {
00682                 out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]);
00683                 out_str[curr_out_len++] = (base64[((a << 4) & 0x30)
00684                                             + ((b >> 4) & 0xf)]);
00685                 out_str[curr_out_len++] = (base64[((b << 2) & 0x3c)
00686                                             + ((c >> 6) & 0x3)]);
00687                 out_str[curr_out_len++] = '=';
00688             }
00689             else
00690             {
00691                 out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]);
00692                 out_str[curr_out_len++] = (base64[((a << 4) & 0x30)
00693                                             + ((b >> 4) & 0xf)]);
00694                 out_str[curr_out_len++] = '=';
00695                 out_str[curr_out_len++] = '=';
00696             }
00697 
00698             i += 3;
00699 
00700             if ((curr_out_len + 4) > out_len)
00701             {
00702                 return(-1);
00703             }
00704 
00705         }
00706         out_str[curr_out_len] = '\0';
00707     }
00708     
00709     return curr_out_len;
00710 }
00711 
00712 #ifdef TEST_NSHTTPCONN
00713 
00714 int
00715 TestHTTPCB(int aBytesRd, int aTotal)
00716 {
00717     DUMP(("Bytes rd: %d\tTotal: %d\n", aBytesRd, aTotal));
00718     return 0;
00719 }
00720 
00721 int
00722 main(int argc, char **argv)
00723 {
00724     nsHTTPConn *conn;
00725     int rv = nsHTTPConn::OK;
00726     char *proxiedURL = NULL;
00727     char *proxyUser = NULL;
00728     char *proxyPswd = NULL;
00729 
00730     DUMP(("*** %s: A self-test for the nsHTTPConn class.\n", argv[0]));
00731 
00732     if (argc < 2)
00733     {
00734         printf("usage: %s <http_url> [<proxied_url> [<proxy_user> ", argv[0]);
00735         printf("<proxy_pswd>]]\n");
00736         exit(1);
00737     }
00738 
00739     conn = new nsHTTPConn(argv[1]);
00740 
00741     if (argc >= 3)
00742     {
00743         proxiedURL = argv[2];
00744     }
00745     if (argc >= 5)
00746     {
00747         proxyUser = argv[3];
00748         proxyPswd = argv[4];
00749     }
00750 
00751     conn->SetProxyInfo(proxiedURL, proxyUser, proxyPswd);
00752 
00753     rv = conn->Open();
00754     DUMP(("nsHTTPConn::Open returned: %d\n", rv));
00755 
00756     rv = conn->Get(TestHTTPCB, NULL); // NULL: local file name = URL leaf
00757     DUMP(("nsHTTPConn::Get returned: %d\n", rv));
00758 
00759     rv = conn->Close();
00760     DUMP(("nsHTTPConn::Close returned: %d\n", rv));
00761 
00762     return 0;
00763 }
00764 
00765 #endif /* TEST_NSHTTPCONN */