michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef __nsFtpState__h_ michael@0: #define __nsFtpState__h_ michael@0: michael@0: #include "nsBaseContentStream.h" michael@0: michael@0: #include "nsICacheListener.h" michael@0: #include "nsString.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIAsyncInputStream.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsITransport.h" michael@0: #include "mozilla/net/DNS.h" michael@0: #include "nsFtpControlConnection.h" michael@0: #include "nsIProtocolProxyCallback.h" michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "nsINetworkManager.h" michael@0: #include "nsProxyRelease.h" michael@0: #endif michael@0: michael@0: // ftp server types michael@0: #define FTP_GENERIC_TYPE 0 michael@0: #define FTP_UNIX_TYPE 1 michael@0: #define FTP_VMS_TYPE 8 michael@0: #define FTP_NT_TYPE 9 michael@0: #define FTP_OS2_TYPE 11 michael@0: michael@0: // ftp states michael@0: typedef enum _FTP_STATE { michael@0: /////////////////////// michael@0: //// Internal states michael@0: FTP_INIT, michael@0: FTP_WAIT_CACHE, michael@0: FTP_READ_CACHE, michael@0: FTP_COMMAND_CONNECT, michael@0: FTP_READ_BUF, michael@0: FTP_ERROR, michael@0: FTP_COMPLETE, michael@0: michael@0: /////////////////////// michael@0: //// Command channel connection setup states michael@0: FTP_S_USER, FTP_R_USER, michael@0: FTP_S_PASS, FTP_R_PASS, michael@0: FTP_S_SYST, FTP_R_SYST, michael@0: FTP_S_ACCT, FTP_R_ACCT, michael@0: FTP_S_TYPE, FTP_R_TYPE, michael@0: FTP_S_CWD, FTP_R_CWD, michael@0: FTP_S_SIZE, FTP_R_SIZE, michael@0: FTP_S_MDTM, FTP_R_MDTM, michael@0: FTP_S_REST, FTP_R_REST, michael@0: FTP_S_RETR, FTP_R_RETR, michael@0: FTP_S_STOR, FTP_R_STOR, michael@0: FTP_S_LIST, FTP_R_LIST, michael@0: FTP_S_PASV, FTP_R_PASV, michael@0: FTP_S_PWD, FTP_R_PWD, michael@0: FTP_S_FEAT, FTP_R_FEAT, michael@0: FTP_S_OPTS, FTP_R_OPTS michael@0: } FTP_STATE; michael@0: michael@0: // higher level ftp actions michael@0: typedef enum _FTP_ACTION {GET, PUT} FTP_ACTION; michael@0: michael@0: class nsFtpChannel; michael@0: class nsICancelable; michael@0: class nsICacheEntryDescriptor; michael@0: class nsIProxyInfo; michael@0: class nsIStreamListener; michael@0: michael@0: // The nsFtpState object is the content stream for the channel. It implements michael@0: // nsIInputStreamCallback, so it can read data from the control connection. It michael@0: // implements nsITransportEventSink so it can mix status events from both the michael@0: // control connection and the data connection. michael@0: michael@0: class nsFtpState : public nsBaseContentStream, michael@0: public nsIInputStreamCallback, michael@0: public nsITransportEventSink, michael@0: public nsICacheListener, michael@0: public nsIRequestObserver, michael@0: public nsFtpControlConnectionListener, michael@0: public nsIProtocolProxyCallback michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIINPUTSTREAMCALLBACK michael@0: NS_DECL_NSITRANSPORTEVENTSINK michael@0: NS_DECL_NSICACHELISTENER michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSIPROTOCOLPROXYCALLBACK michael@0: michael@0: // Override input stream methods: michael@0: NS_IMETHOD CloseWithStatus(nsresult status); michael@0: NS_IMETHOD Available(uint64_t *result); michael@0: NS_IMETHOD ReadSegments(nsWriteSegmentFun fun, void *closure, michael@0: uint32_t count, uint32_t *result); michael@0: michael@0: // nsFtpControlConnectionListener methods: michael@0: virtual void OnControlDataAvailable(const char *data, uint32_t dataLen); michael@0: virtual void OnControlError(nsresult status); michael@0: michael@0: nsFtpState(); michael@0: nsresult Init(nsFtpChannel *channel); michael@0: michael@0: protected: michael@0: // Notification from nsBaseContentStream::AsyncWait michael@0: virtual void OnCallbackPending(); michael@0: michael@0: private: michael@0: virtual ~nsFtpState(); michael@0: michael@0: /////////////////////////////////// michael@0: // BEGIN: STATE METHODS michael@0: nsresult S_user(); FTP_STATE R_user(); michael@0: nsresult S_pass(); FTP_STATE R_pass(); michael@0: nsresult S_syst(); FTP_STATE R_syst(); michael@0: nsresult S_acct(); FTP_STATE R_acct(); michael@0: michael@0: nsresult S_type(); FTP_STATE R_type(); michael@0: nsresult S_cwd(); FTP_STATE R_cwd(); michael@0: michael@0: nsresult S_size(); FTP_STATE R_size(); michael@0: nsresult S_mdtm(); FTP_STATE R_mdtm(); michael@0: nsresult S_list(); FTP_STATE R_list(); michael@0: michael@0: nsresult S_rest(); FTP_STATE R_rest(); michael@0: nsresult S_retr(); FTP_STATE R_retr(); michael@0: nsresult S_stor(); FTP_STATE R_stor(); michael@0: nsresult S_pasv(); FTP_STATE R_pasv(); michael@0: nsresult S_pwd(); FTP_STATE R_pwd(); michael@0: nsresult S_feat(); FTP_STATE R_feat(); michael@0: nsresult S_opts(); FTP_STATE R_opts(); michael@0: // END: STATE METHODS michael@0: /////////////////////////////////// michael@0: michael@0: // internal methods michael@0: void MoveToNextState(FTP_STATE nextState); michael@0: nsresult Process(); michael@0: michael@0: void KillControlConnection(); michael@0: nsresult StopProcessing(); michael@0: nsresult EstablishControlConnection(); michael@0: nsresult SendFTPCommand(const nsCSubstring& command); michael@0: void ConvertFilespecToVMS(nsCString& fileSpec); michael@0: void ConvertDirspecToVMS(nsCString& fileSpec); michael@0: void ConvertDirspecFromVMS(nsCString& fileSpec); michael@0: nsresult BuildStreamConverter(nsIStreamListener** convertStreamListener); michael@0: nsresult SetContentType(); michael@0: michael@0: /** michael@0: * This method is called to kick-off the FTP state machine. mState is michael@0: * reset to FTP_COMMAND_CONNECT, and the FTP state machine progresses from michael@0: * there. This method is initially called (indirectly) from the channel's michael@0: * AsyncOpen implementation. michael@0: */ michael@0: void Connect(); michael@0: michael@0: /** michael@0: * This method opens a cache entry for reading or writing depending on the michael@0: * state of the channel and of the system (e.g., opened for reading if we michael@0: * are offline). This method is responsible for setting mCacheEntry if michael@0: * there is a cache entry that can be used. It returns true if it ends up michael@0: * waiting (asynchronously) for access to the cache entry. In that case, michael@0: * the nsFtpState's OnCacheEntryAvailable method will be called once the michael@0: * cache entry is available or if an error occurs. michael@0: */ michael@0: bool CheckCache(); michael@0: michael@0: /** michael@0: * This method returns true if the data for this URL can be read from the michael@0: * cache. This method assumes that mCacheEntry is non-null. michael@0: */ michael@0: bool CanReadCacheEntry(); michael@0: michael@0: /** michael@0: * This method causes the cache entry to be read. Data from the cache michael@0: * entry will be fed to the channel's listener. This method returns true michael@0: * if successfully reading from the cache. This method assumes that michael@0: * mCacheEntry is non-null and opened with read access. michael@0: */ michael@0: bool ReadCacheEntry(); michael@0: michael@0: /** michael@0: * This method configures mDataStream with an asynchronous input stream to michael@0: * the cache entry. The cache entry is read on a background thread. This michael@0: * method assumes that mCacheEntry is non-null and opened with read access. michael@0: */ michael@0: nsresult OpenCacheDataStream(); michael@0: michael@0: /** michael@0: * This method inserts the cache entry's output stream into the stream michael@0: * listener chain for the FTP channel. As a result, the cache entry michael@0: * receives data as data is pushed to the channel's listener. This method michael@0: * assumes that mCacheEntry is non-null and opened with write access. michael@0: */ michael@0: nsresult InstallCacheListener(); michael@0: michael@0: /////////////////////////////////// michael@0: // Private members michael@0: michael@0: // ****** state machine vars michael@0: FTP_STATE mState; // the current state michael@0: FTP_STATE mNextState; // the next state michael@0: bool mKeepRunning; // thread event loop boolean michael@0: int32_t mResponseCode; // the last command response code michael@0: nsCString mResponseMsg; // the last command response text michael@0: michael@0: // ****** channel/transport/stream vars michael@0: nsRefPtr mControlConnection; // cacheable control connection (owns mCPipe) michael@0: bool mReceivedControlData; michael@0: bool mTryingCachedControl; // retrying the password michael@0: bool mRETRFailed; // Did we already try a RETR and it failed? michael@0: uint64_t mFileSize; michael@0: nsCString mModTime; michael@0: michael@0: // ****** consumer vars michael@0: nsRefPtr mChannel; // our owning FTP channel we pass through our events michael@0: nsCOMPtr mProxyInfo; michael@0: michael@0: // ****** connection cache vars michael@0: int32_t mServerType; // What kind of server are we talking to michael@0: michael@0: // ****** protocol interpretation related state vars michael@0: nsString mUsername; // username michael@0: nsString mPassword; // password michael@0: FTP_ACTION mAction; // the higher level action (GET/PUT) michael@0: bool mAnonymous; // try connecting anonymous (default) michael@0: bool mRetryPass; // retrying the password michael@0: bool mStorReplyReceived; // FALSE if waiting for STOR michael@0: // completion status from server michael@0: nsresult mInternalError; // represents internal state errors michael@0: bool mReconnectAndLoginAgain; michael@0: bool mCacheConnection; michael@0: michael@0: // ****** URI vars michael@0: int32_t mPort; // the port to connect to michael@0: nsString mFilename; // url filename (if any) michael@0: nsCString mPath; // the url's path michael@0: nsCString mPwd; // login Path michael@0: michael@0: // ****** other vars michael@0: nsCOMPtr mDataTransport; michael@0: nsCOMPtr mDataStream; michael@0: nsCOMPtr mUploadRequest; michael@0: bool mAddressChecked; michael@0: bool mServerIsIPv6; michael@0: bool mUseUTF8; michael@0: michael@0: static uint32_t mSessionStartTime; michael@0: michael@0: mozilla::net::NetAddr mServerAddress; michael@0: michael@0: // ***** control read gvars michael@0: nsresult mControlStatus; michael@0: nsCString mControlReadCarryOverBuf; michael@0: michael@0: nsCOMPtr mCacheEntry; michael@0: bool mDoomCache; michael@0: michael@0: nsCString mSuppliedEntityID; michael@0: michael@0: nsCOMPtr mProxyRequest; michael@0: bool mDeferredCallbackPending; michael@0: michael@0: // These members are used for network per-app metering (bug 855948) michael@0: // Currently, they are only available on gonk. michael@0: uint64_t mCountRecv; michael@0: #ifdef MOZ_WIDGET_GONK michael@0: nsMainThreadPtrHandle mActiveNetwork; michael@0: #endif michael@0: nsresult SaveNetworkStats(bool); michael@0: void CountRecvBytes(uint64_t recvBytes) michael@0: { michael@0: mCountRecv += recvBytes; michael@0: SaveNetworkStats(false); michael@0: } michael@0: }; michael@0: michael@0: #endif //__nsFtpState__h_