Bug 26767 - FTP client detects UTF-8 if server returns UTF8 on FEAT. r=michal.novotny

This commit is contained in:
Makoto Kato 2014-04-23 01:12:58 +09:00
Родитель df5eac109e
Коммит d20c2455e3
4 изменённых файлов: 110 добавлений и 12 удалений

Просмотреть файл

@ -92,6 +92,7 @@ nsFtpState::nsFtpState()
, mPort(21) , mPort(21)
, mAddressChecked(false) , mAddressChecked(false)
, mServerIsIPv6(false) , mServerIsIPv6(false)
, mUseUTF8(false)
, mControlStatus(NS_OK) , mControlStatus(NS_OK)
, mDeferredCallbackPending(false) , mDeferredCallbackPending(false)
{ {
@ -276,7 +277,12 @@ nsFtpState::EstablishControlConnection()
mServerType = mControlConnection->mServerType; mServerType = mControlConnection->mServerType;
mPassword = mControlConnection->mPassword; mPassword = mControlConnection->mPassword;
mPwd = mControlConnection->mPwd; mPwd = mControlConnection->mPwd;
mUseUTF8 = mControlConnection->mUseUTF8;
mTryingCachedControl = true; mTryingCachedControl = true;
// we have to set charset to connection if server supports utf-8
if (mUseUTF8)
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
// we're already connected to this server, skip login. // we're already connected to this server, skip login.
mState = FTP_S_PASV; mState = FTP_S_PASV;
@ -646,7 +652,43 @@ nsFtpState::Process()
mInternalError = NS_ERROR_FTP_PWD; mInternalError = NS_ERROR_FTP_PWD;
break; break;
// FEAT for RFC2640 support
case FTP_S_FEAT:
rv = S_feat();
if (NS_FAILED(rv))
mInternalError = rv;
MoveToNextState(FTP_R_FEAT);
break;
case FTP_R_FEAT:
mState = R_feat();
// Don't want to overwrite a more explicit status code
if (FTP_ERROR == mState && NS_SUCCEEDED(mInternalError))
mInternalError = NS_ERROR_FAILURE;
break;
// OPTS for some non-RFC2640-compliant servers support
case FTP_S_OPTS:
rv = S_opts();
if (NS_FAILED(rv))
mInternalError = rv;
MoveToNextState(FTP_R_OPTS);
break;
case FTP_R_OPTS:
mState = R_opts();
// Don't want to overwrite a more explicit status code
if (FTP_ERROR == mState && NS_SUCCEEDED(mInternalError))
mInternalError = NS_ERROR_FAILURE;
break;
default: default:
; ;
@ -923,7 +965,7 @@ nsFtpState::R_syst() {
return FTP_ERROR; return FTP_ERROR;
} }
return FTP_S_PWD; return FTP_S_FEAT;
} }
if (mResponseCode/100 == 5) { if (mResponseCode/100 == 5) {
@ -931,7 +973,7 @@ nsFtpState::R_syst() {
// No clue. We will just hope it is UNIX type server. // No clue. We will just hope it is UNIX type server.
mServerType = FTP_UNIX_TYPE; mServerType = FTP_UNIX_TYPE;
return FTP_S_PWD; return FTP_S_FEAT;
} }
return FTP_ERROR; return FTP_ERROR;
} }
@ -1135,6 +1177,10 @@ nsFtpState::S_list() {
serverType.AppendInt(mServerType); serverType.AppendInt(mServerType);
mCacheEntry->SetMetaDataElement("servertype", serverType.get()); mCacheEntry->SetMetaDataElement("servertype", serverType.get());
nsAutoCString useUTF8;
useUTF8.AppendInt(mUseUTF8);
mCacheEntry->SetMetaDataElement("useUTF8", useUTF8.get());
// open cache entry for writing, and configure it to receive data. // open cache entry for writing, and configure it to receive data.
if (NS_FAILED(InstallCacheListener())) { if (NS_FAILED(InstallCacheListener())) {
mCacheEntry->AsyncDoom(nullptr); mCacheEntry->AsyncDoom(nullptr);
@ -1551,6 +1597,39 @@ nsFtpState::R_pasv() {
return FTP_S_SIZE; return FTP_S_SIZE;
} }
nsresult
nsFtpState::S_feat() {
return SendFTPCommand(NS_LITERAL_CSTRING("FEAT" CRLF));
}
FTP_STATE
nsFtpState::R_feat() {
if (mResponseCode/100 == 2) {
if (mResponseMsg.Find(NS_LITERAL_CSTRING(CRLF " UTF8" CRLF), true) > -1) {
// This FTP server supports UTF-8 encoding
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
mUseUTF8 = true;
return FTP_S_OPTS;
}
}
mUseUTF8 = false;
return FTP_S_PWD;
}
nsresult
nsFtpState::S_opts() {
// This command is for compatibility of old FTP spec (IETF Draft)
return SendFTPCommand(NS_LITERAL_CSTRING("OPTS UTF8 ON" CRLF));
}
FTP_STATE
nsFtpState::R_opts() {
// Ignore error code because "OPTS UTF8 ON" is for compatibility of
// FTP server using IETF draft
return FTP_S_PWD;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsIRequest methods: // nsIRequest methods:
@ -1847,6 +1926,7 @@ nsFtpState::KillControlConnection()
mControlConnection->mServerType = mServerType; mControlConnection->mServerType = mServerType;
mControlConnection->mPassword = mPassword; mControlConnection->mPassword = mPassword;
mControlConnection->mPwd = mPwd; mControlConnection->mPwd = mPwd;
mControlConnection->mUseUTF8 = mUseUTF8;
nsresult rv = NS_OK; nsresult rv = NS_OK;
// Don't cache controlconnection if anonymous (bug #473371) // Don't cache controlconnection if anonymous (bug #473371)
@ -1865,7 +1945,7 @@ nsFtpState::KillControlConnection()
class nsFtpAsyncAlert : public nsRunnable class nsFtpAsyncAlert : public nsRunnable
{ {
public: public:
nsFtpAsyncAlert(nsIPrompt *aPrompter, nsACString& aResponseMsg) nsFtpAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
: mPrompter(aPrompter) : mPrompter(aPrompter)
, mResponseMsg(aResponseMsg) , mResponseMsg(aResponseMsg)
{ {
@ -1878,15 +1958,15 @@ public:
NS_IMETHOD Run() NS_IMETHOD Run()
{ {
if (mPrompter) { if (mPrompter) {
mPrompter->Alert(nullptr, NS_ConvertASCIItoUTF16(mResponseMsg).get()); mPrompter->Alert(nullptr, mResponseMsg.get());
} }
return NS_OK; return NS_OK;
} }
private: private:
nsCOMPtr<nsIPrompt> mPrompter; nsCOMPtr<nsIPrompt> mPrompter;
nsCString mResponseMsg; nsString mResponseMsg;
}; };
nsresult nsresult
nsFtpState::StopProcessing() nsFtpState::StopProcessing()
@ -1910,8 +1990,14 @@ nsFtpState::StopProcessing()
nsCOMPtr<nsIPrompt> prompter; nsCOMPtr<nsIPrompt> prompter;
mChannel->GetCallback(prompter); mChannel->GetCallback(prompter);
if (prompter) { if (prompter) {
nsCOMPtr<nsIRunnable> alertEvent = nsCOMPtr<nsIRunnable> alertEvent;
new nsFtpAsyncAlert(prompter, mResponseMsg); if (mUseUTF8) {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertUTF8toUTF16(mResponseMsg));
} else {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertASCIItoUTF16(mResponseMsg));
}
NS_DispatchToMainThread(alertEvent, NS_DISPATCH_NORMAL); NS_DispatchToMainThread(alertEvent, NS_DISPATCH_NORMAL);
} }
} }
@ -2372,6 +2458,12 @@ nsFtpState::ReadCacheEntry()
nsAutoCString serverNum(serverType.get()); nsAutoCString serverNum(serverType.get());
nsresult err; nsresult err;
mServerType = serverNum.ToInteger(&err); mServerType = serverNum.ToInteger(&err);
nsXPIDLCString charset;
mCacheEntry->GetMetaDataElement("useUTF8", getter_Copies(charset));
const char *useUTF8 = charset.get();
if (useUTF8 && atoi(useUTF8) == 1)
mChannel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
mChannel->PushStreamConverter("text/ftp-dir", mChannel->PushStreamConverter("text/ftp-dir",
APPLICATION_HTTP_INDEX_FORMAT); APPLICATION_HTTP_INDEX_FORMAT);

Просмотреть файл

@ -57,7 +57,9 @@ typedef enum _FTP_STATE {
FTP_S_STOR, FTP_R_STOR, FTP_S_STOR, FTP_R_STOR,
FTP_S_LIST, FTP_R_LIST, FTP_S_LIST, FTP_R_LIST,
FTP_S_PASV, FTP_R_PASV, FTP_S_PASV, FTP_R_PASV,
FTP_S_PWD, FTP_R_PWD FTP_S_PWD, FTP_R_PWD,
FTP_S_FEAT, FTP_R_FEAT,
FTP_S_OPTS, FTP_R_OPTS
} FTP_STATE; } FTP_STATE;
// higher level ftp actions // higher level ftp actions
@ -129,6 +131,8 @@ private:
nsresult S_stor(); FTP_STATE R_stor(); nsresult S_stor(); FTP_STATE R_stor();
nsresult S_pasv(); FTP_STATE R_pasv(); nsresult S_pasv(); FTP_STATE R_pasv();
nsresult S_pwd(); FTP_STATE R_pwd(); nsresult S_pwd(); FTP_STATE R_pwd();
nsresult S_feat(); FTP_STATE R_feat();
nsresult S_opts(); FTP_STATE R_opts();
// END: STATE METHODS // END: STATE METHODS
/////////////////////////////////// ///////////////////////////////////
@ -243,6 +247,7 @@ private:
nsCOMPtr<nsIRequest> mUploadRequest; nsCOMPtr<nsIRequest> mUploadRequest;
bool mAddressChecked; bool mAddressChecked;
bool mServerIsIPv6; bool mServerIsIPv6;
bool mUseUTF8;
static uint32_t mSessionStartTime; static uint32_t mSessionStartTime;

Просмотреть файл

@ -65,8 +65,8 @@ nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream)
nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host, nsFtpControlConnection::nsFtpControlConnection(const nsCSubstring& host,
uint32_t port) uint32_t port)
: mServerType(0), mSessionId(gFtpHandler->GetSessionId()), mHost(host) : mServerType(0), mSessionId(gFtpHandler->GetSessionId())
, mPort(port) , mUseUTF8(false), mHost(host), mPort(port)
{ {
LOG_ALWAYS(("FTP:CC created @%p", this)); LOG_ALWAYS(("FTP:CC created @%p", this));
} }

Просмотреть файл

@ -68,6 +68,7 @@ public:
int32_t mSuspendedWrite; int32_t mSuspendedWrite;
nsCString mPwd; nsCString mPwd;
uint32_t mSessionId; uint32_t mSessionId;
bool mUseUTF8;
private: private:
nsCString mHost; nsCString mHost;