diff --git a/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp b/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp index f2954f81627..e69de29bb2d 100644 --- a/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp +++ b/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp @@ -1,765 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Samir Gehani - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include -#include -#include -#include -#include -#include "nsHTTPConn.h" -#include "nsSocket.h" - -const char kHTTPProto[8] = "http://"; -const char kFTPProto[8] = "ftp://"; -const int kHTTPPort = 80; -const int kFTPPort = 21; -const int kRespBufSize = 1024; -const int kReqBufSize = 4096; -const int kHdrBufSize = 4096; -const char kCRLF[3] = "\r\n"; -const char kHdrBodyDelim[5] = "\r\n\r\n"; -const char kDefaultDestFile[11] = "index.html"; - -nsHTTPConn::nsHTTPConn(char *aHost, int aPort, char *aPath, int (*aEventPumpCB)(void)): - mEventPumpCB(aEventPumpCB), - mHost(aHost), - mPath(aPath), - mProxiedURL(NULL), - mProxyUser(NULL), - mProxyPswd(NULL), - mDestFile(NULL), - mHostPathAllocd(FALSE), - mSocket(NULL) -{ - if (aPort <= 0) - mPort = kHTTPPort; - else - mPort = aPort; - - DUMP(("mHost = %s\n", mHost)); - DUMP(("mPort = %d\n", mPort)); - DUMP(("mPath = %s\n", mPath)); -} - -nsHTTPConn::nsHTTPConn(char *aHost, int aPort, char *aPath) : - mEventPumpCB(NULL), - mHost(aHost), - mPath(aPath), - mProxiedURL(NULL), - mProxyUser(NULL), - mProxyPswd(NULL), - mDestFile(NULL), - mHostPathAllocd(FALSE), - mSocket(NULL) -{ - if (aPort <= 0) - mPort = kHTTPPort; - else - mPort = aPort; - - DUMP(("mHost = %s\n", mHost)); - DUMP(("mPort = %d\n", mPort)); - DUMP(("mPath = %s\n", mPath)); -} - -nsHTTPConn::nsHTTPConn(char *aURL, int (*aEventPumpCB)(void)) : - mEventPumpCB(aEventPumpCB), - mPort(kHTTPPort), - mProxiedURL(NULL), - mProxyUser(NULL), - mProxyPswd(NULL), - mDestFile(NULL), - mHostPathAllocd(FALSE), - mSocket(NULL), - mResponseCode(0) -{ - // parse URL - if (ParseURL(kHTTPProto, aURL, &mHost, &mPort, &mPath) == OK) - mHostPathAllocd = TRUE; - else - { - mHost = NULL; - mPath = NULL; - } - - DUMP(("mHost = %s\n", mHost)); - DUMP(("mPort = %d\n", mPort)); - DUMP(("mPath = %s\n", mPath)); -} - -nsHTTPConn::nsHTTPConn(char *aURL) : - mEventPumpCB(NULL), - mPort(kHTTPPort), - mProxiedURL(NULL), - mProxyUser(NULL), - mProxyPswd(NULL), - mDestFile(NULL), - mHostPathAllocd(FALSE), - mSocket(NULL), - mResponseCode(0) -{ - // parse URL - if (ParseURL(kHTTPProto, aURL, &mHost, &mPort, &mPath) == OK) - mHostPathAllocd = TRUE; - else - { - mHost = NULL; - mPath = NULL; - } - - DUMP(("mHost = %s\n", mHost)); - DUMP(("mPort = %d\n", mPort)); - DUMP(("mPath = %s\n", mPath)); -} - -nsHTTPConn::~nsHTTPConn() -{ - if (mHostPathAllocd) - { - if (mHost) - free(mHost); - if (mPath) - free(mPath); - } -} - -int -nsHTTPConn::Open() -{ - // verify host && path - if (!mHost || !mPath) - return E_MALFORMED_URL; - - // create socket - mSocket = new nsSocket(mHost, mPort, mEventPumpCB); - if (!mSocket) - return E_MEM; - - // open socket - return mSocket->Open(); -} - -int -nsHTTPConn::ResumeOrGet(HTTPGetCB aCallback, char *aDestFile) -{ - struct stat stbuf; - int rv = 0; - int resPos = 0; - - if (!aDestFile) - return E_PARAM; - - /* stat local file */ - rv = stat(aDestFile, &stbuf); - if (rv == 0) - resPos = stbuf.st_size; - - return Get(aCallback, aDestFile, resPos); - - // XXX TO DO: - // XXX handle proxies -} - -int -nsHTTPConn::Get(HTTPGetCB aCallback, char *aDestFile) -{ - // deprecated API; wrapper for backwards compatibility - - return ResumeOrGet(aCallback, aDestFile); -} - -int -nsHTTPConn::Get(HTTPGetCB aCallback, char *aDestFile, int aResumePos) -{ - int rv; - char *pathToUse; - - // verify host && path - if (!mHost || !mPath) - return E_MALFORMED_URL; - - if (!aDestFile) - { - if (mProxiedURL) - pathToUse = mProxiedURL; - else - pathToUse = mPath; - - // no leaf: assume default file 'index.html' - if (*(pathToUse + strlen(pathToUse) - 1) == '/') - aDestFile = (char *) kDefaultDestFile; - else - aDestFile = strrchr(pathToUse, '/') + 1; - } - - // issue request - rv = Request(aResumePos); - - // recv response - if (rv == OK) - rv = Response(aCallback, aDestFile, aResumePos); - - return rv; -} - -int -nsHTTPConn::Close() -{ - int rv; - - // close socket - rv = mSocket->Close(); - - // destroy socket - delete mSocket; - - return rv; -} - -void -nsHTTPConn::SetProxyInfo(char *aProxiedURL, char *aProxyUser, - char *aProxyPswd) -{ - mProxiedURL = aProxiedURL; - mProxyUser = aProxyUser; - mProxyPswd = aProxyPswd; -} - -int -nsHTTPConn::Request(int aResumePos) -{ - char req[kReqBufSize]; - char hdr[kHdrBufSize]; - int rv; - - memset(req, 0, kReqBufSize); - - // format header buf: - - // request line - memset(hdr, 0, kHdrBufSize); - if (mProxiedURL) - { - char *host = NULL, *path = NULL; - char proto[8]; - int port; -#ifdef DEBUG - assert(sizeof hdr > (strlen(mProxiedURL) + 15 )); -#endif - sprintf(hdr, "GET %s HTTP/1.0%s", mProxiedURL, kCRLF); - strcpy(req, hdr); - if (strncmp(mProxiedURL, kFTPProto, strlen(kFTPProto)) == 0) - { - strcpy(proto,kFTPProto); - port = kFTPPort; - } - else - { - strcpy(proto,kHTTPProto); - port = kHTTPPort; - } - rv = ParseURL(proto, mProxiedURL, - &host, &port, &path); - if (rv == OK) { - memset(hdr, 0, kHdrBufSize); - sprintf(hdr, "Host: %s:%d%s", host, port, kCRLF); - strcat(req, hdr); - } - if (host) - free(host); - if (path) - free(path); - } - else - { - sprintf(hdr, "GET %s HTTP/1.0%s", mPath, kCRLF); - strcpy(req, hdr); - - memset(hdr, 0, kHdrBufSize); - sprintf(hdr, "Host: %s%s", mHost, kCRLF); - strcat(req, hdr); - } - - // if proxy set and proxy user/pswd set - if (mProxyUser && mProxyPswd) - { - char *usrPsd = (char *) malloc(strlen(mProxyUser) + - strlen(":") + - strlen(mProxyPswd) + 1); - if (!usrPsd) - return E_MEM; - sprintf(usrPsd, "%s:%s", mProxyUser, mProxyPswd); - - // base 64 encode proxy header - char usrPsdEncoded[128]; // pray that 128 is long enough - memset(usrPsdEncoded, 0, 128); - - DUMP(("Unencoded string: %s\n", usrPsd)); - rv = Base64Encode((const unsigned char *)usrPsd, strlen(usrPsd), - usrPsdEncoded, 128); - DUMP(("Encoded string: %s\n", usrPsdEncoded)); - DUMP(("Base64Encode returned: %d\n", rv)); - if (rv <= 0) - { - return E_B64_ENCODE; - } - - // append proxy header to header buf - memset(hdr, 0, kHdrBufSize); - sprintf(hdr, "Proxy-authorization: Basic %s%s", usrPsdEncoded, kCRLF); - strcat(req, hdr); - - // XXX append host with port 21 if ftp - - } - - // byte range support - if (aResumePos > 0) - { - sprintf(hdr, "Range: bytes=%d-%s", aResumePos, kCRLF); - strcat(req, hdr); - } - - // headers all done so indicate - strcat(req, kCRLF); - - // send header buf over socket - int bufSize = strlen(req); - rv = mSocket->Send((unsigned char *) req, &bufSize); - DUMP(("\n\n%s", req)); - - if (bufSize != (int) strlen(req)) - rv = E_REQ_INCOMPLETE; - - return rv; -} - -int -nsHTTPConn::Response(HTTPGetCB aCallback, char *aDestFile, int aResumePos) -{ - // NOTE: overwrites dest file if it already exists - - int rv = OK; - char resp[kRespBufSize]; - int bufSize, total = 0, fwriteLen, fwrote, bytesWritten = 0, expectedSize = 0; - FILE *destFd; - char *fwritePos; - int bFirstIter = TRUE; - - if (!aDestFile) - return E_PARAM; - - // open dest file - if (aResumePos > 0) - { - destFd = fopen(aDestFile, "r+b"); - if (!destFd) - return E_OPEN_FILE; - - if (fseek(destFd, aResumePos, SEEK_SET) != 0) - { - fclose(destFd); - return E_SEEK_FILE; - } - } - else - { - destFd = fopen(aDestFile, "w+b"); - if (!destFd) - return E_OPEN_FILE; - } - - // iteratively recv response - do - { - memset(resp, 0, kRespBufSize); - bufSize = kRespBufSize; - - rv = mSocket->Recv((unsigned char *) resp, &bufSize); - DUMP(("nsSocket::Recv returned: %d\t and recd: %d\n", rv, bufSize)); - - if(rv == nsSocket::E_EOF_FOUND || (rv != nsSocket::E_READ_MORE && rv != nsSocket::OK) ) { - break; - } - - if (bFirstIter) - { - fwritePos = strstr(resp, kHdrBodyDelim); - if (fwritePos == NULL) - { - // XXX no header! should we handle? - fwritePos = resp; - fwriteLen = bufSize; - } - else - { - ParseResponseCode((const char *)resp, &mResponseCode); - - if ( mResponseCode < 200 || mResponseCode >=300 ) - { - // if we don't get a response code in the 200 range then fail - // TODO: handle the response codes in the 300 range - rv = nsHTTPConn::E_HTTP_RESPONSE; - break; - } - - ParseContentLength((const char *)resp, &expectedSize); - - // move past hdr-body delimiter - fwritePos += strlen(kHdrBodyDelim); - fwriteLen = bufSize - (fwritePos - resp); - total = expectedSize + aResumePos; - } - - bFirstIter = FALSE; - } - else - { - fwritePos = resp; - fwriteLen = bufSize; - } - - fwrote = fwrite(fwritePos, sizeof(char), fwriteLen, destFd); - assert(fwrote == fwriteLen); - - if (fwriteLen > 0) - bytesWritten += fwriteLen; - if (aCallback && - (aCallback(bytesWritten, total) == E_USER_CANCEL)) - rv = E_USER_CANCEL; // we want to ignore all errors returned - // from aCallback() except E_USER_CANCEL - - if ( mEventPumpCB ) - mEventPumpCB(); - - } while ( rv == nsSocket::E_READ_MORE || rv == nsSocket::OK); - - if ( bytesWritten == expectedSize && rv != nsHTTPConn::E_HTTP_RESPONSE) - rv = nsSocket::E_EOF_FOUND; - - if (rv == nsSocket::E_EOF_FOUND) - { - DUMP(("EOF detected\n")); - rv = OK; - } - - fclose(destFd); - - return rv; -} - -int -nsHTTPConn::ParseURL(const char *aProto, char *aURL, char **aHost, - int *aPort, char **aPath) -{ - if (!aURL || !aHost || !aPort || !aPath || !aProto) - return E_PARAM; - - char *pos, *nextSlash, *nextColon, *end, *hostEnd; - int protoLen = strlen(aProto); - - if ((strncmp(aURL, aProto, protoLen) != 0) || - (strlen(aURL) < 9)) - return E_MALFORMED_URL; - - pos = aURL + protoLen; - nextColon = strchr(pos, ':'); - nextSlash = strchr(pos, '/'); - - // optional port specification - if (nextColon && ((nextSlash && nextColon < nextSlash) || - !nextSlash)) - { - int portStrLen; - if (nextSlash) - portStrLen = nextSlash - nextColon; - else - portStrLen = strlen(nextColon); - - char *portStr = (char *) malloc(portStrLen + 1); - if (!portStr) - return E_MEM; - memset(portStr, 0, portStrLen + 1); - strncpy(portStr, nextColon+1, portStrLen); - *aPort = atoi(portStr); - free(portStr); - } - if ( (!nextColon || (nextSlash && (nextColon > nextSlash))) - && *aPort <= 0) // don't override port if already set - *aPort = -1; - - // only host in URL, assume '/' for path - if (!nextSlash) - { - int copyLen; - if (nextColon) - copyLen = nextColon - pos; - else - copyLen = strlen(pos); - - *aHost = (char *) malloc(copyLen + 1); // to NULL terminate - if (!aHost) - return E_MEM; - memset(*aHost, 0, copyLen + 1); - strncpy(*aHost, pos, copyLen); - - *aPath = (char *) malloc(2); - strcpy(*aPath, "/"); - - return OK; - } - - // normal parsing: both host and path exist - if (nextColon) - hostEnd = nextColon; - else - hostEnd = nextSlash; - *aHost = (char *) malloc(hostEnd - pos + 1); // to NULL terminate - if (!*aHost) - return E_MEM; - memset(*aHost, 0, hostEnd - pos + 1); - strncpy(*aHost, pos, hostEnd - pos); - *(*aHost + (hostEnd - pos)) = 0; // NULL terminate - - pos = nextSlash; - end = aURL + strlen(aURL); - - *aPath = (char *) malloc(end - pos + 1); - if (!*aPath) - { - if (*aHost) - free(*aHost); - return E_MEM; - } - memset(*aPath, 0, end - pos + 1); - strncpy(*aPath, pos, end - pos); - - return OK; -} - -void -nsHTTPConn::ParseResponseCode(const char *aBuf, int *aCode) -{ - char codeStr[4]; - const char *pos; - - if (!aBuf || !aCode) - return; - - // make sure the beginning of the buffer is the HTTP status code - if (strncmp(aBuf,"HTTP/",5) == 0) - { - pos = strstr(aBuf," "); // find the space before the code - ++pos; // move to the beginning of the code - strncpy((char *)codeStr,pos, 3); - codeStr[3] = '\0'; - *aCode = atoi(codeStr); - } -} - -void -nsHTTPConn::ParseContentLength(const char *aBuf, int *aLength) -{ - const char *clHdr; // Content-length header line start - const char *eol, *pos; - char clNameStr1[16] = "Content-length:"; - char clNameStr2[16] = "Content-Length:"; - char *clNameStr = clNameStr1; - - if (!aBuf || !aLength) - return; // non fatal so no error codes returned - *aLength = 0; - - // XXX strcasestr() needs to be ported for Solaris (and Win32 and Mac?) - clHdr = strstr(aBuf, (char *)clNameStr1); - if (!clHdr) - { - clHdr = strstr(aBuf, (char *)clNameStr2); - clNameStr = clNameStr2; - } - if (clHdr) - { - eol = strstr(clHdr, kCRLF); // end of line - pos = clHdr + strlen(clNameStr); - while ((pos < eol) && (*pos == ' ' || *pos == '\t')) - pos++; - if (pos < eol) - { - int clValStrLen = eol - pos + 1; // extra byte to NULL terminate - char *clValStr = (char *) malloc(clValStrLen); - if (!clValStr) - return; // imminent doom! - - memset(clValStr, 0, clValStrLen); - strncpy(clValStr, pos, eol - pos); - *aLength = atoi(clValStr); - } - } -} - -int -nsHTTPConn::Base64Encode(const unsigned char *in_str, int in_len, - char *out_str, int out_len) -{ - // NOTE: shamelessly copied from nsAbSyncPostEngine.cpp - - static unsigned char base64[] = - { - /* 0 1 2 3 4 5 6 7 */ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */ - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ - 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */ - '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */ - }; - - int curr_out_len = 0; - - int i = 0; - unsigned char a, b, c; - - out_str[0] = '\0'; - - if (in_len > 0) - { - - while (i < in_len) - { - a = in_str[i]; - b = (i + 1 >= in_len) ? 0 : in_str[i + 1]; - c = (i + 2 >= in_len) ? 0 : in_str[i + 2]; - - if (i + 2 < in_len) - { - out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); - out_str[curr_out_len++] = (base64[((a << 4) & 0x30) - + ((b >> 4) & 0xf)]); - out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) - + ((c >> 6) & 0x3)]); - out_str[curr_out_len++] = (base64[c & 0x3F]); - } - else if (i + 1 < in_len) - { - out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); - out_str[curr_out_len++] = (base64[((a << 4) & 0x30) - + ((b >> 4) & 0xf)]); - out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) - + ((c >> 6) & 0x3)]); - out_str[curr_out_len++] = '='; - } - else - { - out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); - out_str[curr_out_len++] = (base64[((a << 4) & 0x30) - + ((b >> 4) & 0xf)]); - out_str[curr_out_len++] = '='; - out_str[curr_out_len++] = '='; - } - - i += 3; - - if ((curr_out_len + 4) > out_len) - { - return(-1); - } - - } - out_str[curr_out_len] = '\0'; - } - - return curr_out_len; -} - -#ifdef TEST_NSHTTPCONN - -int -TestHTTPCB(int aBytesRd, int aTotal) -{ - DUMP(("Bytes rd: %d\tTotal: %d\n", aBytesRd, aTotal)); - return 0; -} - -int -main(int argc, char **argv) -{ - nsHTTPConn *conn; - int rv = nsHTTPConn::OK; - char *proxiedURL = NULL; - char *proxyUser = NULL; - char *proxyPswd = NULL; - - DUMP(("*** %s: A self-test for the nsHTTPConn class.\n", argv[0])); - - if (argc < 2) - { - printf("usage: %s [ [ ", argv[0]); - printf("]]\n"); - exit(1); - } - - conn = new nsHTTPConn(argv[1]); - - if (argc >= 3) - { - proxiedURL = argv[2]; - } - if (argc >= 5) - { - proxyUser = argv[3]; - proxyPswd = argv[4]; - } - - conn->SetProxyInfo(proxiedURL, proxyUser, proxyPswd); - - rv = conn->Open(); - DUMP(("nsHTTPConn::Open returned: %d\n", rv)); - - rv = conn->Get(TestHTTPCB, NULL); // NULL: local file name = URL leaf - DUMP(("nsHTTPConn::Get returned: %d\n", rv)); - - rv = conn->Close(); - DUMP(("nsHTTPConn::Close returned: %d\n", rv)); - - return 0; -} - -#endif /* TEST_NSHTTPCONN */