diff --git a/netwerk/protocol/http/src/makefile.win b/netwerk/protocol/http/src/makefile.win index 4ede57df050e..3b331f2a3a66 100644 --- a/netwerk/protocol/http/src/makefile.win +++ b/netwerk/protocol/http/src/makefile.win @@ -49,7 +49,6 @@ CPP_OBJS= \ .\$(OBJDIR)\nsHTTPHandlerFactory.obj \ .\$(OBJDIR)\nsHTTPConnection.obj \ .\$(OBJDIR)\nsHTTPRequest.obj \ - .\$(OBJDIR)\nsHTTPRequestObserver.obj \ .\$(OBJDIR)\nsHTTPResponseListener.obj \ .\$(OBJDIR)\nsHTTPResponse.obj \ $(NULL) diff --git a/netwerk/protocol/http/src/nsHTTPConnection.cpp b/netwerk/protocol/http/src/nsHTTPConnection.cpp index ce55aae76057..6baaaed3330e 100644 --- a/netwerk/protocol/http/src/nsHTTPConnection.cpp +++ b/netwerk/protocol/http/src/nsHTTPConnection.cpp @@ -22,6 +22,7 @@ #include "nsIHTTPHandler.h" #include "nsHTTPRequest.h" #include "nsHTTPResponse.h" +#include "nsITransport.h" nsHTTPConnection::nsHTTPConnection( nsIURL* i_URL, @@ -49,6 +50,7 @@ nsHTTPConnection::nsHTTPConnection( m_pRequest = new nsHTTPRequest(m_pURL); if (!m_pRequest) NS_ERROR("unable to create new nsHTTPRequest!"); + m_pRequest->SetConnection(this); } @@ -90,7 +92,13 @@ nsHTTPConnection::Resume(void) NS_METHOD nsHTTPConnection::GetInputStream(nsIInputStream* *o_Stream) { - return NS_ERROR_NOT_IMPLEMENTED; + if (!m_bConnected) + Open(); + // How do I block here? + if (m_pResponse) + return m_pResponse->GetInputStream(o_Stream); + return NS_OK; // change to error ? or block till response is set up? + } NS_METHOD @@ -130,9 +138,44 @@ nsHTTPConnection::Open(void) if (m_bConnected || (m_State > HS_IDLE)) return NS_ERROR_ALREADY_CONNECTED; - m_bConnected = PR_TRUE; + // Set up a new request observer and a response listener and pass to teh transport + nsresult rv = NS_OK; - return NS_ERROR_NOT_IMPLEMENTED; + const char* host; + rv = m_pURL->GetHost(&host); + if (NS_FAILED(rv)) return rv; + + PRInt32 port; + rv = m_pURL->GetPort(&port); + if (NS_FAILED(rv)) return rv; + nsITransport* temp; + + if (port == -1) + { + m_pHandler->GetDefaultPort(&port); + } + + NS_ASSERTION(port>0, "Bad port setting!"); + PRUint32 unsignedPort = port; + + rv = m_pHandler->GetTransport(host, unsignedPort, &temp); + if (temp) + { + m_pRequest->SetTransport(temp); + + nsIInputStream* stream; + //Get the stream where it will read the request data from + m_pRequest->GetInputStream(&stream); + + rv = temp->AsyncWrite(stream, (nsISupports*)(nsIProtocolConnection*)this , m_pEventQ, m_pRequest); + + m_State = HS_WAITING_FOR_RESPONSE; + m_bConnected = PR_TRUE; + } + else + NS_ERROR("Failed to create/get a transport!"); + + return rv; } NS_METHOD diff --git a/netwerk/protocol/http/src/nsHTTPConnection.h b/netwerk/protocol/http/src/nsHTTPConnection.h index 017646afe34f..8035d17586b2 100644 --- a/netwerk/protocol/http/src/nsHTTPConnection.h +++ b/netwerk/protocol/http/src/nsHTTPConnection.h @@ -94,6 +94,9 @@ public: NS_IMETHOD GetURL(nsIURL* *o_URL) const; NS_IMETHOD EventSink(nsIHTTPEventSink* *o_EventSink) const { if (o_EventSink) *o_EventSink = m_pEventSink; return NS_OK; }; + + nsIEventQueue* EventQueue(void) const { return m_pEventQ; }; + private: nsCOMPtr m_pURL; PRBool m_bConnected; diff --git a/netwerk/protocol/http/src/nsHTTPHandler.cpp b/netwerk/protocol/http/src/nsHTTPHandler.cpp index e42f1414a9be..6a398ac5b326 100644 --- a/netwerk/protocol/http/src/nsHTTPHandler.cpp +++ b/netwerk/protocol/http/src/nsHTTPHandler.cpp @@ -26,7 +26,7 @@ #include "nsITransport.h" #include "nsISocketTransportService.h" #include "nsIServiceManager.h" -#include "nsIHTTPEventSink.h" +#include "nsIHttpEventSink.h" static NS_DEFINE_CID(kStandardUrlCID, NS_STANDARDURL_CID); static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); @@ -42,12 +42,14 @@ NS_METHOD CreateOrGetHTTPHandler(nsIHTTPHandler* *o_HTTPHandler) } nsHTTPHandler::nsHTTPHandler(): - m_pTransportTable(nsnull), + m_pTransportTable(new nsHashtable()), mRefCnt(0) { if (NS_FAILED(NS_NewISupportsArray(getter_AddRefs(m_pConnections)))) { NS_ERROR("unable to create new ISupportsArray"); } + if (!m_pTransportTable) + NS_ERROR("Failed to create a new transport table"); } nsHTTPHandler::~nsHTTPHandler() @@ -106,8 +108,10 @@ nsHTTPHandler::NewConnection(nsIURL* i_URL, if (pNewInstance) { NS_ADDREF(pNewInstance); - *o_Instance = pNewInstance; + pNewInstance->QueryInterface(nsIProtocolConnection::GetIID(), (void**)o_Instance); // add this instance to the active list of connections + // TODO! + NS_RELEASE(pNewInstance); return NS_OK; } else @@ -215,6 +219,8 @@ nsHTTPHandler::GetTransport(const char* i_Host, NS_ASSERTION(oldValue == nsnull, "Race condition in transport table!"); NS_ADDREF(trans); + *o_pTrans = trans; + return rv; } diff --git a/netwerk/protocol/http/src/nsHTTPHandler.h b/netwerk/protocol/http/src/nsHTTPHandler.h index 19c8ff039292..036020b3ad44 100644 --- a/netwerk/protocol/http/src/nsHTTPHandler.h +++ b/netwerk/protocol/http/src/nsHTTPHandler.h @@ -45,7 +45,7 @@ class nsHashtable; class nsITransport; -class nsHTTPHandler : public nsIHTTPHandler, public nsIProtocolHandler +class nsHTTPHandler : public nsIHTTPHandler //, public nsIProxy { @@ -119,6 +119,7 @@ public: return pHandler; }; + // Functions from nsIHTTPHandler /* Pull out an existing transport from the hashtable, or if none exists create one. diff --git a/netwerk/protocol/http/src/nsHTTPRequest.cpp b/netwerk/protocol/http/src/nsHTTPRequest.cpp index 75858215921b..84b9340be4a8 100644 --- a/netwerk/protocol/http/src/nsHTTPRequest.cpp +++ b/netwerk/protocol/http/src/nsHTTPRequest.cpp @@ -22,15 +22,24 @@ #include "nsHeaderPair.h" #include "kHTTPHeaders.h" #include "nsHTTPEnums.h" +#include "nsIByteBufferInputStream.h" +#include "plstr.h" +#include "nsString.h" +#include "nsITransport.h" +#include "nsHTTPConnection.h" +#include "nsHTTPResponseListener.h" -nsHTTPRequest::nsHTTPRequest(nsIUrl* i_pURL, HTTPMethod i_Method): +nsHTTPRequest::nsHTTPRequest(nsIUrl* i_pURL, HTTPMethod i_Method, nsITransport* i_pTransport): m_pURI(i_pURL), m_Method(i_Method), m_pArray(new nsVoidArray()), m_Version(HTTP_ONE_ZERO), - m_Request(nsnull) + m_Request(nsnull), + m_pTransport(i_pTransport), + mRefCnt(0) { - Build(); + + //Build(); } nsHTTPRequest::~nsHTTPRequest() @@ -45,6 +54,17 @@ nsHTTPRequest::~nsHTTPRequest() delete m_pArray; m_pArray = 0; } + if (m_Request) + { + delete m_Request; + m_Request = 0; + } +/* + if (m_pTransport) + NS_RELEASE(m_pTransport); + if (m_pConnection) + NS_RELEASE(m_pConnection); +*/ } NS_IMPL_ADDREF(nsHTTPRequest); @@ -52,7 +72,72 @@ NS_IMPL_ADDREF(nsHTTPRequest); nsresult nsHTTPRequest::Build() { - return NS_OK; + if (m_Request) + NS_ERROR("Request already built!"); + nsresult rv = NS_NewByteBufferInputStream(&m_Request); + if (m_Request) + { + + char lineBuffer[1024]; // verify this length! + PRUint32 bytesWritten = 0; + + // Do the first line + const char* methodString = MethodToString(m_Method); + PL_strncpyz(lineBuffer, methodString, PL_strlen(methodString) +1); + const char* filename; + NS_ASSERTION(m_pURI, "No URL to build request for!"); + rv = m_pURI->GetPath(&filename); + PL_strcat(lineBuffer, filename); + PL_strcat(lineBuffer, " HTTP/1.1\n"); + +/* switch (m_Method) + { + case HM_GET: + PL_strncpy(lineBuffer, MethodToString(m_Method) + break; + case HM_DELETE: + case HM_HEAD: + case HM_INDEX: + case HM_LINK: + case HM_OPTIONS: + case HM_POST: + case HM_PUT: + case HM_PATCH: + case HM_TRACE: + case HM_UNLINK: + NS_ERROR_NOT_IMPLEMENTED; + break; + default: NS_ERROR("No method set on request!"); + break; + } +*/ + // Write the request method and HTTP version + + // Add additional headers if any + if (m_pArray && (0< m_pArray->Count())) + { + for (PRInt32 i = m_pArray->Count() - 1; i >= 0; --i) + { + nsHeaderPair* element = NS_STATIC_CAST(nsHeaderPair*, m_pArray->ElementAt(i)); + //Copy header, put a ": " and then the value + LF + // sprintf would be easier... todo change + nsString lineBuffStr; + element->atom->ToString(lineBuffStr); + lineBuffStr.Append(": "); + lineBuffStr.Append((const nsString&)*element->value); + lineBuffStr.Append('\n'); + NS_ASSERTION((lineBuffStr.Length() <= 1024), "Increase line buffer length!"); + lineBuffStr.ToCString(lineBuffer, lineBuffStr.Length()); + lineBuffer[lineBuffStr.Length()] = '\0'; + rv = m_Request->Fill(lineBuffer, PL_strlen(lineBuffer), &bytesWritten); + if (NS_FAILED(rv)) return rv; + lineBuffer[0] = '\0'; + } + } + + } + + return rv; } nsresult @@ -70,6 +155,11 @@ nsHTTPRequest::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(nsIStreamObserver::GetIID())) { + *aInstancePtr = (void*) ((nsIStreamObserver*)this); + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(nsIHTTPCommonHeaders::GetIID())) { *aInstancePtr = (void*) ((nsIHTTPCommonHeaders*)this); NS_ADDREF_THIS(); @@ -740,4 +830,72 @@ nsHTTPRequest::GetHTTPVersion(HTTPVersion* o_Version) const { *o_Version = m_Version; return NS_OK; +} + +NS_METHOD +nsHTTPRequest::GetInputStream(nsIInputStream* *o_Stream) +{ + if (o_Stream) + { + if (!m_Request) + { + Build(); + } + m_Request->QueryInterface(nsIInputStream::GetIID(), (void**)o_Stream); + return NS_OK; + } + else + return NS_ERROR_NULL_POINTER; + +} + +NS_IMETHODIMP +nsHTTPRequest::OnStartBinding(nsISupports* i_pContext) +{ + //TODO globally replace printf with trace calls. + //printf("nsHTTPRequest::OnStartBinding...\n"); + + return NS_OK; +} + +NS_IMETHODIMP +nsHTTPRequest::OnStopBinding(nsISupports* i_pContext, + nsresult iStatus, + nsIString* i_pMsg) +{ + //printf("nsHTTPRequest::OnStopBinding...\n"); + // if we could write successfully... + if (NS_SUCCEEDED(iStatus)) + { + //Prepare to receive the response! + nsHTTPResponseListener* pListener = new nsHTTPResponseListener(); + m_pTransport->AsyncRead( + i_pContext, + m_pConnection->EventQueue(), + pListener); + //TODO check this portion here... + return pListener ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + + /* + Somewhere here we need to send a message up the event sink + that we successfully (or not) have sent request to the + server. TODO + */ + return iStatus; +} + +NS_IMETHODIMP +nsHTTPRequest::SetTransport(nsITransport* i_pTransport) +{ + NS_ASSERTION(!m_pTransport, "Transport being overwritten!"); + m_pTransport = i_pTransport; + return NS_OK; +} + +NS_IMETHODIMP +nsHTTPRequest::SetConnection(nsHTTPConnection* i_pConnection) +{ + m_pConnection = i_pConnection; + return NS_OK; } \ No newline at end of file diff --git a/netwerk/protocol/http/src/nsHTTPRequest.h b/netwerk/protocol/http/src/nsHTTPRequest.h index 2f9c9f252248..edcb5beba980 100644 --- a/netwerk/protocol/http/src/nsHTTPRequest.h +++ b/netwerk/protocol/http/src/nsHTTPRequest.h @@ -21,26 +21,43 @@ #include "nsIHTTPCommonHeaders.h" #include "nsIHTTPRequest.h" +#include "nsIStreamObserver.h" +class nsIInputStream; class nsIUrl; class nsVoidArray; +class nsIByteBufferInputStream; +class nsITransport; +class nsHTTPConnection; + /* The nsHTTPRequest class is the request object created for each HTTP request before the connection. A request object may be cloned and saved for later reuse. + This is also the observer class for writing to the transport. This + receives notifications of OnStartBinding and OnStopBinding as the + request is being written out to the server. Each instance of this + class is tied to the corresponding transport that it writes the + request to. + + The essential purpose of the observer portion is to create the + response listener once it is done writing a request and also notify + the handler when this is done writing a request out. The latter could + be used (later) to do pipelining. + This class is internal to the protocol handler implementation and should theroetically not be used by the app or the core netlib. -Gagan Saksena 03/29/99 */ -class nsHTTPRequest : public nsIHTTPRequest +class nsHTTPRequest : public nsIHTTPRequest , public nsIStreamObserver { public: // Constructor and destructor - nsHTTPRequest(nsIUrl* i_URL=0, HTTPMethod i_Method=HM_GET); + nsHTTPRequest(nsIUrl* i_URL=0, HTTPMethod i_Method=HM_GET, nsITransport* i_pTranport = nsnull); virtual ~nsHTTPRequest(); // Methods from nsISupports @@ -220,6 +237,13 @@ public: NS_IMETHOD SetUserAgent(const char* i_Value); NS_IMETHOD GetUserAgent(const char* *o_Value) const; + // nsIStreamObserver functions + NS_IMETHOD OnStartBinding(nsISupports* context); + + NS_IMETHOD OnStopBinding(nsISupports* context, + nsresult aStatus, + nsIString* aMsg); + // Finally our own methods... /* Clone the current request for later use. Release it @@ -232,7 +256,16 @@ public: NS_IMETHOD SetPriority(); // TODO NS_IMETHOD GetPriority(); //TODO + + /* + Returns the stream set up to hold the request data + Calls build if not already built. + */ + NS_IMETHOD GetInputStream(nsIInputStream* *o_Stream); + NS_IMETHOD SetTransport(nsITransport* i_pTransport); + + NS_IMETHOD SetConnection(nsHTTPConnection* i_pConnection); protected: @@ -244,17 +277,17 @@ protected: { static const char methods[][TOTAL_NUMBER_OF_METHODS] = { - "DELETE", - "GET", - "HEAD", - "INDEX", - "LINK", - "OPTIONS", - "POST", - "PUT", - "PATCH", - "TRACE", - "UNLINK" + "DELETE ", + "GET ", + "HEAD ", + "INDEX ", + "LINK ", + "OPTIONS ", + "POST ", + "PUT ", + "PATCH ", + "TRACE ", + "UNLINK " }; return methods[i_Method]; @@ -263,9 +296,11 @@ protected: nsIUrl* m_pURI; HTTPVersion m_Version; HTTPMethod m_Method; - // The actual request string! - char* m_Request; + // The actual request stream! + nsIByteBufferInputStream* m_Request; nsVoidArray* m_pArray; + nsITransport* m_pTransport; + nsHTTPConnection* m_pConnection; }; #endif /* _nsHTTPRequest_h_ */ diff --git a/netwerk/protocol/http/src/nsHTTPResponse.cpp b/netwerk/protocol/http/src/nsHTTPResponse.cpp index 7e8483e70975..3bf539314abb 100644 --- a/netwerk/protocol/http/src/nsHTTPResponse.cpp +++ b/netwerk/protocol/http/src/nsHTTPResponse.cpp @@ -26,8 +26,9 @@ #include "kHTTPHeaders.h" #include "plstr.h" -nsHTTPResponse::nsHTTPResponse(nsIHTTPConnection* i_pCon): - m_pConn(dont_QueryInterface(i_pCon)) +nsHTTPResponse::nsHTTPResponse(nsIHTTPConnection* i_pCon, nsIInputStream* i_InputStream): + m_pConn(dont_QueryInterface(i_pCon)), + m_pInputStream(i_InputStream) { } @@ -502,4 +503,11 @@ nsHTTPResponse::SetStatusString(const char* i_Status) m_pStatusString = new char[len+1]; PL_strncpy(m_pStatusString, i_Status, len); return NS_OK; +} + +NS_METHOD +nsHTTPResponse::GetInputStream(nsIInputStream* *o_Stream) +{ + *o_Stream = m_pInputStream; + return NS_OK; } \ No newline at end of file diff --git a/netwerk/protocol/http/src/nsHTTPResponse.h b/netwerk/protocol/http/src/nsHTTPResponse.h index 558fbd5f7821..f8dbafba847c 100644 --- a/netwerk/protocol/http/src/nsHTTPResponse.h +++ b/netwerk/protocol/http/src/nsHTTPResponse.h @@ -26,6 +26,7 @@ class nsIUrl; class nsVoidArray; +class nsIInputStream; /* The nsHTTPResponse class is the response object created by the response @@ -41,7 +42,7 @@ class nsHTTPResponse : public nsIHTTPResponse public: // Constructor and destructor - nsHTTPResponse(nsIHTTPConnection* i_pConnection); + nsHTTPResponse(nsIHTTPConnection* i_pConnection, nsIInputStream* i_InputStream); virtual ~nsHTTPResponse(); // Methods from nsISupports @@ -160,6 +161,7 @@ public: NS_IMETHOD SetServerVersion(const char* i_ServerVersion); + NS_IMETHOD GetInputStream(nsIInputStream* *o_Stream); protected: NS_IMETHOD SetHeaderInternal(const char* i_Header, const char* i_Value); @@ -172,6 +174,7 @@ protected: HTTPVersion m_ServerVersion; char* m_pStatusString; PRUint32 m_Status; + nsIInputStream* m_pInputStream; friend class nsHTTPResponseListener; }; diff --git a/netwerk/protocol/http/src/nsHTTPResponseListener.cpp b/netwerk/protocol/http/src/nsHTTPResponseListener.cpp index 044a0efcd149..35e2baa3e11c 100644 --- a/netwerk/protocol/http/src/nsHTTPResponseListener.cpp +++ b/netwerk/protocol/http/src/nsHTTPResponseListener.cpp @@ -55,6 +55,18 @@ nsHTTPResponseListener::OnDataAvailable(nsISupports* context, static int extrabufferlen = 0; NS_ASSERTION(i_pStream, "Fake stream!"); + // Set up the response + if (!m_pResponse) + { + m_pResponse = new nsHTTPResponse (m_pConnection, i_pStream); + if (!m_pResponse) + { + NS_ERROR("Failed to create the response object!"); + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(m_pResponse); + } + //printf("nsHTTPResponseListener::OnDataAvailable...\n"); /* Check its current state, @@ -123,15 +135,13 @@ nsHTTPResponseListener::OnStartBinding(nsISupports* i_pContext) //printf("nsHTTPResponseListener::OnStartBinding...\n"); m_pConnection = NS_STATIC_CAST(nsIHTTPConnection*, i_pContext); NS_ADDREF(m_pConnection); - // Set up the response - m_pResponse = new nsHTTPResponse (m_pConnection); - if (!m_pResponse) - { - NS_ERROR("Failed to create the response object!"); - return NS_ERROR_OUT_OF_MEMORY; - } - NS_ADDREF(m_pResponse); - + + nsIHTTPEventSink* pSink= nsnull; + nsresult rv = m_pConnection->EventSink(&pSink); + if (NS_FAILED(rv)) + NS_ERROR("No HTTP Event Sink!"); + rv = pSink->OnStartBinding(i_pContext); + return NS_OK; }