Fixes bug 72312 "gopher needs to wrap the proxy channel"

patch=bbaetz, r=dougt, sr=darin
This commit is contained in:
darin%netscape.com 2001-03-30 03:21:55 +00:00
parent 3293dd7eac
commit 8befa3803a
4 changed files with 234 additions and 115 deletions

View File

@ -36,10 +36,15 @@
#include "nsITXTToHTMLConv.h"
#include "nsIProgressEventSink.h"
#include "nsNetUtil.h"
#include "prlog.h"
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
#ifdef PR_LOGGING
extern PRLogModuleInfo* gGopherLog;
#endif
#define BUFFER_SEG_SIZE (4*1024)
#define BUFFER_MAX_SIZE (64*1024)
@ -48,19 +53,28 @@ nsGopherChannel::nsGopherChannel()
: mContentLength(-1),
mActAsObserver(PR_TRUE),
mType(-1),
mStatus(NS_OK)
mStatus(NS_OK),
mProxyPort(-1),
mProxyTransparent(PR_FALSE)
{
NS_INIT_REFCNT();
}
nsGopherChannel::~nsGopherChannel() {
nsGopherChannel::~nsGopherChannel()
{
#ifdef PR_LOGGING
nsXPIDLCString spec;
mUrl->GetSpec(getter_Copies(spec));
PR_LOG(gGopherLog, PR_LOG_ALWAYS, ("~nsGopherChannel() for %s", spec.get()));
#endif
}
NS_IMPL_THREADSAFE_ISUPPORTS4(nsGopherChannel,
NS_IMPL_THREADSAFE_ISUPPORTS5(nsGopherChannel,
nsIChannel,
nsIRequest,
nsIStreamListener,
nsIStreamObserver);
nsIStreamObserver,
nsIProxy);
nsresult
nsGopherChannel::Init(nsIURI* uri)
@ -103,30 +117,102 @@ nsGopherChannel::Init(nsIURI* uri)
mSelector = nsUnescape(NS_CONST_CAST(char*,&buffer[2]));
}
//printf("Host: mHost = %s, mPort = %d\n", mHost.get(), mPort);
//printf("Status: mType = %c, mSelector = %s\n", mType, mSelector.get());
PR_LOG(gGopherLog,
PR_LOG_DEBUG,
("Host: mHost = %s, mPort = %d\n", mHost.get(), mPort));
PR_LOG(gGopherLog,
PR_LOG_DEBUG,
("Status: mType = %c, mSelector = %s\n", mType, mSelector.get()));
return NS_OK;
}
nsresult
nsGopherChannel::SetProxyChannel(nsIChannel *aChannel)
{
mProxyChannel = aChannel;
return NS_OK;
}
NS_METHOD
nsGopherChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
{
nsGopherChannel* fc = new nsGopherChannel();
if (!fc)
nsGopherChannel* gc = new nsGopherChannel();
if (!gc)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(fc);
nsresult rv = fc->QueryInterface(aIID, aResult);
NS_RELEASE(fc);
NS_ADDREF(gc);
nsresult rv = gc->QueryInterface(aIID, aResult);
NS_RELEASE(gc);
return rv;
}
// nsIProxy methods:
NS_IMETHODIMP
nsGopherChannel::GetProxyHost(char **aProxyHost)
{
*aProxyHost = mProxyHost.ToNewCString();
if (!*aProxyHost) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::SetProxyHost(const char * aProxyHost)
{
mProxyHost = aProxyHost;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::GetProxyPort(PRInt32 *aProxyPort)
{
*aProxyPort = mProxyPort;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::SetProxyPort(PRInt32 aProxyPort)
{
mProxyPort = aProxyPort;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::GetProxyType(char **aProxyType)
{
*aProxyType = mProxyType.ToNewCString();
if (!*aProxyType) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::SetProxyType(const char * aProxyType)
{
if (!nsCRT::strcasecmp(aProxyType, "socks")) {
mProxyTransparent = PR_TRUE;
} else {
mProxyTransparent = PR_FALSE;
}
mProxyType = aProxyType;
return NS_OK;
}
nsresult
nsGopherChannel::GetUsingProxy(PRBool *aUsingProxy)
{
if (!aUsingProxy)
return NS_ERROR_NULL_POINTER;
*aUsingProxy = (!mProxyHost.IsEmpty() && !mProxyTransparent);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIRequest methods:
NS_IMETHODIMP
nsGopherChannel::GetName(PRUnichar* *result)
{
if (mProxyChannel)
return mProxyChannel->GetName(result);
nsString name;
name.AppendWithConversion(mHost);
name.AppendWithConversion(":");
@ -138,6 +224,8 @@ nsGopherChannel::GetName(PRUnichar* *result)
NS_IMETHODIMP
nsGopherChannel::IsPending(PRBool *result)
{
if (mProxyChannel)
return mProxyChannel->IsPending(result);
NS_NOTREACHED("nsGopherChannel::IsPending");
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -152,19 +240,28 @@ nsGopherChannel::GetStatus(nsresult *status)
NS_IMETHODIMP
nsGopherChannel::Cancel(nsresult status)
{
PR_LOG(gGopherLog,
PR_LOG_DEBUG,
("nsGopherChannel::Cancel() called [this=%x, status=%x]\n",
this,status));
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
nsresult rv = NS_ERROR_FAILURE;
mStatus = status;
if (mTransportRequest) {
rv = mTransportRequest->Cancel(status);
if (mProxyChannel)
return mProxyChannel->Cancel(status);
else if (mTransportRequest) {
return mTransportRequest->Cancel(status);
}
return rv;
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsGopherChannel::Suspend(void)
{
if (mProxyChannel)
return mProxyChannel->Suspend();
NS_NOTREACHED("nsGopherChannel::Suspend");
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -172,6 +269,8 @@ nsGopherChannel::Suspend(void)
NS_IMETHODIMP
nsGopherChannel::Resume(void)
{
if (mProxyChannel)
return mProxyChannel->Resume();
NS_NOTREACHED("nsGopherChannel::Resume");
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -214,6 +313,9 @@ nsGopherChannel::Open(nsIInputStream **_retval)
{
nsresult rv = NS_OK;
if (mProxyChannel)
return mProxyChannel->Open(_retval);
NS_WITH_SERVICE(nsISocketTransportService,
socketService,
kSocketTransportServiceCID,
@ -239,7 +341,21 @@ nsGopherChannel::Open(nsIInputStream **_retval)
NS_IMETHODIMP
nsGopherChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
{
nsresult rv = NS_OK;
PR_LOG(gGopherLog, PR_LOG_DEBUG, ("nsGopherChannel::AsyncOpen() called [this=%x]\n",
this));
mListener = aListener;
mResponseContext = ctxt;
nsresult rv;
if (mLoadGroup) {
rv = mLoadGroup->AddRequest(this, nsnull);
if (NS_FAILED(rv)) return rv;
}
if (mProxyChannel)
return mProxyChannel->AsyncOpen(this, ctxt);
NS_WITH_SERVICE(nsISocketTransportService,
socketService,
@ -259,15 +375,14 @@ nsGopherChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
mTransport->SetNotificationCallbacks(mCallbacks,
(mLoadAttributes & LOAD_BACKGROUND));
mListener = aListener;
mResponseContext = ctxt;
return SendRequest(mTransport);
}
NS_IMETHODIMP
nsGopherChannel::GetLoadAttributes(PRUint32 *aLoadAttributes)
{
if (mProxyChannel)
mProxyChannel->GetLoadAttributes(aLoadAttributes);
*aLoadAttributes = mLoadAttributes;
return NS_OK;
}
@ -275,12 +390,18 @@ nsGopherChannel::GetLoadAttributes(PRUint32 *aLoadAttributes)
NS_IMETHODIMP
nsGopherChannel::SetLoadAttributes(PRUint32 aLoadAttributes)
{
if (mProxyChannel)
mProxyChannel->SetLoadAttributes(aLoadAttributes);
mLoadAttributes = aLoadAttributes;
return NS_OK;
}
NS_IMETHODIMP
nsGopherChannel::GetContentType(char* *aContentType) {
nsGopherChannel::GetContentType(char* *aContentType)
{
if (mProxyChannel)
return mProxyChannel->GetContentType(aContentType);
if (!aContentType) return NS_ERROR_NULL_POINTER;
switch(mType) {
@ -306,7 +427,7 @@ nsGopherChannel::GetContentType(char* *aContentType) {
case '6':
*aContentType = nsCRT::strdup(APPLICATION_UUENCODE);
break;
case '7': // search - unhandled yet
case '7': // search - returns a directory listing, not handled yet
*aContentType = nsCRT::strdup(TEXT_HTML);
break;
case '8': // telnet - type doesn't make sense
@ -412,8 +533,14 @@ nsGopherChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
// nsIStreamObserver methods
NS_IMETHODIMP
nsGopherChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) {
if (!mActAsObserver) {
nsGopherChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
PR_LOG(gGopherLog,
PR_LOG_DEBUG,
("nsGopherChannel::OnStartRequest called [this=%x, aRequest=%x]\n",
this, aRequest));
if (!mActAsObserver || mProxyChannel) {
// acting as a listener
return mListener->OnStartRequest(this, aContext);
} else {
@ -427,25 +554,33 @@ NS_IMETHODIMP
nsGopherChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
nsresult aStatus, const PRUnichar* aStatusArg)
{
PR_LOG(gGopherLog,
PR_LOG_DEBUG,
("nsGopherChannel::OnStopRequest called [this=%x, aRequest=%x, aStatus=%x]\n",
this,aRequest,aStatus));
nsresult rv = NS_OK;
if (NS_FAILED(aStatus) || !mActAsObserver) {
if (NS_SUCCEEDED(rv) && mLoadGroup) {
rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus, aStatusArg);
}
if (NS_FAILED(aStatus)) // let the original caller know
if (NS_FAILED(aStatus) || !mActAsObserver || mProxyChannel) {
if (NS_FAILED(aStatus) || mProxyChannel) // let the original caller know
aContext=mResponseContext;
rv = mListener->OnStopRequest(this, aContext, aStatus, aStatusArg);
mListener = 0;
if (mListener) {
rv = mListener->OnStopRequest(this, aContext, aStatus, aStatusArg);
if (NS_FAILED(rv)) return rv;
}
if (mLoadGroup) {
rv = mLoadGroup->RemoveRequest(this, nsnull, aStatus, aStatusArg);
}
mTransport = 0;
return rv;
} else {
// at this point we know the request has been sent.
// we're no longer acting as an observer.
mActAsObserver = PR_FALSE;
nsCOMPtr<nsIStreamListener> converterListener;
NS_WITH_SERVICE(nsIStreamConverterService, StreamConvService,
@ -491,14 +626,16 @@ nsGopherChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
NS_IMETHODIMP
nsGopherChannel::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
nsIInputStream *aInputStream,
PRUint32 aSourceOffset, PRUint32 aLength) {
PRUint32 aSourceOffset, PRUint32 aLength)
{
mContentLength = aLength;
return mListener->OnDataAvailable(this, aContext, aInputStream,
aSourceOffset, aLength);
}
nsresult
nsGopherChannel::SendRequest(nsITransport* aTransport) {
nsGopherChannel::SendRequest(nsITransport* aTransport)
{
nsresult rv = NS_OK;
nsCOMPtr<nsISupports> result;
nsCOMPtr<nsIInputStream> charstream;
@ -517,7 +654,8 @@ nsGopherChannel::SendRequest(nsITransport* aTransport) {
charstream = do_QueryInterface(result, &rv);
if (NS_FAILED(rv)) return rv;
//printf("Sending: %s\n", requestBuffer.GetBuffer());
PR_LOG(gGopherLog,PR_LOG_DEBUG,
("Sending: %s\n", requestBuffer.get()));
rv = NS_AsyncWriteFromStream(getter_AddRefs(mTransportRequest),
aTransport, charstream,

View File

@ -33,15 +33,19 @@
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsGopherHandler.h"
#include "nsIProxy.h"
#include "nsIStreamListener.h"
#include "nsITransport.h"
class nsGopherChannel : public nsIChannel,
public nsIProxy,
public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
NS_DECL_NSIPROXY
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
@ -55,6 +59,8 @@ public:
nsresult Init(nsIURI* uri);
nsresult SetProxyChannel(nsIChannel* aChannel);
nsresult GetUsingProxy(PRBool *aUsingProxy);
protected:
nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
@ -81,7 +87,12 @@ protected:
nsCOMPtr<nsIRequest> mTransportRequest;
nsresult mStatus;
protected:
nsCOMPtr<nsIChannel> mProxyChannel; // a proxy channel
nsCString mProxyHost;
PRInt32 mProxyPort;
nsCString mProxyType;
PRBool mProxyTransparent;
nsresult SendRequest(nsITransport* aTransport);
};

View File

@ -36,6 +36,11 @@
#include "nsIHTTPChannel.h"
#include "nsIErrorService.h"
#include "nsNetUtil.h"
#include "prlog.h"
#ifdef PR_LOGGING
PRLogModuleInfo* gGopherLog = nsnull;
#endif
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kProtocolProxyServiceCID, NS_PROTOCOLPROXYSERVICE_CID);
@ -43,69 +48,36 @@ static NS_DEFINE_CID(kHTTPHandlerCID, NS_IHTTPHANDLER_CID);
////////////////////////////////////////////////////////////////////////////////
nsGopherHandler::nsGopherHandler() : mProxyPort(-1) {
nsGopherHandler::nsGopherHandler() {
NS_INIT_REFCNT();
nsresult rv;
#ifdef PR_LOGGING
if (!gGopherLog)
gGopherLog = PR_NewLogModule("nsGopherProtocol");
#endif
mProxySvc = do_GetService(kProtocolProxyServiceCID, &rv);
if (!mProxySvc)
NS_WARNING("Failed to get proxy service!\n");
}
nsGopherHandler::~nsGopherHandler() {
PR_LOG(gGopherLog, PR_LOG_ALWAYS, ("~nsGopherHandler() called"));
}
NS_IMPL_ISUPPORTS2(nsGopherHandler, nsIProtocolHandler, nsIProxy);
NS_IMPL_THREADSAFE_ISUPPORTS1(nsGopherHandler, nsIProtocolHandler);
NS_METHOD
nsGopherHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) {
nsGopherHandler* ph = new nsGopherHandler();
if (!ph)
nsGopherHandler* gh = new nsGopherHandler();
if (!gh)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(ph);
nsresult rv = ph->QueryInterface(aIID, aResult);
NS_RELEASE(ph);
NS_ADDREF(gh);
nsresult rv = gh->QueryInterface(aIID, aResult);
NS_RELEASE(gh);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
// nsIProxy methods:
NS_IMETHODIMP
nsGopherHandler::GetProxyHost(char **aProxyHost) {
*aProxyHost = mProxyHost.ToNewCString();
if (!*aProxyHost) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsGopherHandler::SetProxyHost(const char * aProxyHost) {
mProxyHost = aProxyHost;
return NS_OK;
}
NS_IMETHODIMP
nsGopherHandler::GetProxyPort(PRInt32 *aProxyPort) {
*aProxyPort = mProxyPort;
return NS_OK;
}
NS_IMETHODIMP
nsGopherHandler::SetProxyPort(PRInt32 aProxyPort) {
mProxyPort = aProxyPort;
return NS_OK;
}
NS_IMETHODIMP
nsGopherHandler::GetProxyType(char **aProxyType) {
*aProxyType = mProxyType.ToNewCString();
if (!*aProxyType) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsGopherHandler::SetProxyType(const char * aProxyType) {
mProxyType = aProxyType;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:
@ -131,7 +103,6 @@ nsGopherHandler::NewURI(const char *aSpec, nsIURI *aBaseURI,
// All gopher URLs are absolute by definition
NS_ASSERTION(!aBaseURI, "base url passed into gopher protocol handler");
// I probably need an nsIGopherURL
nsCOMPtr<nsIStandardURL> url;
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
NS_GET_IID(nsIStandardURL),
@ -147,8 +118,7 @@ nsGopherHandler::NewURI(const char *aSpec, nsIURI *aBaseURI,
NS_IMETHODIMP
nsGopherHandler::NewChannel(nsIURI* url, nsIChannel* *result)
{
nsresult rv;
nsresult rv;
nsGopherChannel* channel;
rv = nsGopherChannel::Create(nsnull, NS_GET_IID(nsIChannel),
(void**)&channel);
@ -156,7 +126,6 @@ nsGopherHandler::NewChannel(nsIURI* url, nsIChannel* *result)
rv = channel->Init(url);
if (NS_FAILED(rv)) {
NS_RELEASE(channel);
return rv;
}
@ -167,14 +136,12 @@ nsGopherHandler::NewChannel(nsIURI* url, nsIChannel* *result)
if (mProxySvc &&
NS_SUCCEEDED(mProxySvc->GetProxyEnabled(&useProxy)) && useProxy) {
rv = mProxySvc->ExamineForProxy(url, this);
rv = mProxySvc->ExamineForProxy(url, channel);
if (NS_FAILED(rv)) return rv;
}
if (mProxyHost.IsEmpty() || mProxyType.Equals("socks")) {
*result = channel;
return NS_OK;
}
useProxy = PR_FALSE;
if (NS_SUCCEEDED(channel->GetUsingProxy(&useProxy)) && useProxy) {
nsCOMPtr<nsIChannel> proxyChannel;
// if an gopher proxy is enabled, push things off to HTTP.
@ -182,7 +149,8 @@ nsGopherHandler::NewChannel(nsIURI* url, nsIChannel* *result)
do_GetService(kHTTPHandlerCID, &rv);
if (NS_FAILED(rv)) return rv;
// rjc says: the dummy URI (for the HTTP layer) needs to be a syntactically valid URI
// rjc says: the dummy URI (for the HTTP layer) needs to be a
// syntactically valid URI
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), "http://example.com");
@ -198,25 +166,35 @@ nsGopherHandler::NewChannel(nsIURI* url, nsIChannel* *result)
rv = url->GetSpec(getter_Copies(spec));
if (NS_FAILED(rv)) return rv;
rv = httpChannel->SetProxyRequestURI((const char*)spec);
rv = httpChannel->SetProxyRequestURI(spec.get());
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIProxy> proxyHTTP = do_QueryInterface(httpChannel, &rv);
if (NS_FAILED(rv)) return rv;
rv = proxyHTTP->SetProxyHost(mProxyHost);
nsXPIDLCString proxyHost;
rv = channel->GetProxyHost(getter_Copies(proxyHost));
if (NS_FAILED(rv)) return rv;
rv = proxyHTTP->SetProxyPort(mProxyPort);
rv = proxyHTTP->SetProxyHost(proxyHost);
if (NS_FAILED(rv)) return rv;
rv = proxyHTTP->SetProxyType(mProxyType);
PRInt32 proxyPort;
rv = channel->GetProxyPort(&proxyPort);
if (NS_FAILED(rv)) return rv;
*result = proxyChannel;
NS_ADDREF(*result);
} else {
*result = channel;
rv = proxyHTTP->SetProxyPort(proxyPort);
if (NS_FAILED(rv)) return rv;
nsXPIDLCString proxyType;
rv = channel->GetProxyType(getter_Copies(proxyType));
if (NS_SUCCEEDED(rv))
proxyHTTP->SetProxyType(proxyType);
rv = channel->SetProxyChannel(proxyChannel);
}
return NS_OK;
*result = channel;
return rv;
}

View File

@ -25,7 +25,6 @@
#include "nsIProtocolHandler.h"
#include "nsIProtocolProxyService.h"
#include "nsIProxy.h"
#include "nsString.h"
#include "nsCOMPtr.h"
@ -37,12 +36,10 @@
{ 0x44588c1f, 0x2ce8, 0x4ad8, \
{0x9b, 0x16, 0xdf, 0xb9, 0xd9, 0xd5, 0x13, 0xa7} }
class nsGopherHandler : public nsIProtocolHandler, public nsIProxy
{
class nsGopherHandler : public nsIProtocolHandler {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIPROXY
// nsGopherHandler methods:
nsGopherHandler();
@ -51,13 +48,8 @@ public:
// Define a Create method to be used with a factory:
static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID,
void* *aResult);
protected:
nsCOMPtr<nsIProtocolProxyService> mProxySvc;
nsCAutoString mProxyHost;
PRInt32 mProxyPort;
nsCAutoString mProxyType;
nsCOMPtr<nsIProtocolProxyService> mProxySvc;
};
#endif /* nsGopherHandler_h___ */