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
parent 375ca3ec4c
commit a3c69f7ea9
4 changed files with 110 additions and 12 deletions

View File

@ -92,6 +92,7 @@ nsFtpState::nsFtpState()
, mPort(21)
, mAddressChecked(false)
, mServerIsIPv6(false)
, mUseUTF8(false)
, mControlStatus(NS_OK)
, mDeferredCallbackPending(false)
{
@ -276,7 +277,12 @@ nsFtpState::EstablishControlConnection()
mServerType = mControlConnection->mServerType;
mPassword = mControlConnection->mPassword;
mPwd = mControlConnection->mPwd;
mUseUTF8 = mControlConnection->mUseUTF8;
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.
mState = FTP_S_PASV;
@ -646,7 +652,43 @@ nsFtpState::Process()
mInternalError = NS_ERROR_FTP_PWD;
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:
;
@ -923,7 +965,7 @@ nsFtpState::R_syst() {
return FTP_ERROR;
}
return FTP_S_PWD;
return FTP_S_FEAT;
}
if (mResponseCode/100 == 5) {
@ -931,7 +973,7 @@ nsFtpState::R_syst() {
// No clue. We will just hope it is UNIX type server.
mServerType = FTP_UNIX_TYPE;
return FTP_S_PWD;
return FTP_S_FEAT;
}
return FTP_ERROR;
}
@ -1135,6 +1177,10 @@ nsFtpState::S_list() {
serverType.AppendInt(mServerType);
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.
if (NS_FAILED(InstallCacheListener())) {
mCacheEntry->AsyncDoom(nullptr);
@ -1551,6 +1597,39 @@ nsFtpState::R_pasv() {
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:
@ -1847,6 +1926,7 @@ nsFtpState::KillControlConnection()
mControlConnection->mServerType = mServerType;
mControlConnection->mPassword = mPassword;
mControlConnection->mPwd = mPwd;
mControlConnection->mUseUTF8 = mUseUTF8;
nsresult rv = NS_OK;
// Don't cache controlconnection if anonymous (bug #473371)
@ -1865,7 +1945,7 @@ nsFtpState::KillControlConnection()
class nsFtpAsyncAlert : public nsRunnable
{
public:
nsFtpAsyncAlert(nsIPrompt *aPrompter, nsACString& aResponseMsg)
nsFtpAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
: mPrompter(aPrompter)
, mResponseMsg(aResponseMsg)
{
@ -1878,15 +1958,15 @@ public:
NS_IMETHOD Run()
{
if (mPrompter) {
mPrompter->Alert(nullptr, NS_ConvertASCIItoUTF16(mResponseMsg).get());
mPrompter->Alert(nullptr, mResponseMsg.get());
}
return NS_OK;
}
private:
nsCOMPtr<nsIPrompt> mPrompter;
nsCString mResponseMsg;
nsString mResponseMsg;
};
nsresult
nsFtpState::StopProcessing()
@ -1910,8 +1990,14 @@ nsFtpState::StopProcessing()
nsCOMPtr<nsIPrompt> prompter;
mChannel->GetCallback(prompter);
if (prompter) {
nsCOMPtr<nsIRunnable> alertEvent =
new nsFtpAsyncAlert(prompter, mResponseMsg);
nsCOMPtr<nsIRunnable> alertEvent;
if (mUseUTF8) {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertUTF8toUTF16(mResponseMsg));
} else {
alertEvent = new nsFtpAsyncAlert(prompter,
NS_ConvertASCIItoUTF16(mResponseMsg));
}
NS_DispatchToMainThread(alertEvent, NS_DISPATCH_NORMAL);
}
}
@ -2372,6 +2458,12 @@ nsFtpState::ReadCacheEntry()
nsAutoCString serverNum(serverType.get());
nsresult 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",
APPLICATION_HTTP_INDEX_FORMAT);

View File

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

View File

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

View File

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