Saturday, December 19, 2009

Библиотека cURL и Gene6 FTP Server

Долгое время пользуюсь cURL и вот столкнулся с ситуацией, когда моё приложение оказалось неспособно залить файл на FTP-сервер, причём раньше таких проблем не было. Проявляется это только для сервера Gene6 FTP Server, а на других, имеющихся у меня, всё работает нормально.

После анализа ситуации выяснилось, что cURL, анализируя результат выполнения операции ожидает от сервера только один ответ, а Gene6 отвечает дважды. Вот лог:

(001517) 12/19/2009 2:25:07 PM - user (192.168.2.12) > APPE TPG.pdf
(001517) 12/19/2009 2:25:07 PM - user (192.168.2.12) > asked to upload 'TPG.pdf' in 'D:\ftp\user\test\ftp\' --> Access allowed.
(001517) 12/19/2009 2:25:07 PM - user (192.168.2.12) > 150 Data connection accepted from 192.168.2.12:3147; transfer starting for TPG.pdf.
(001517) 12/19/2009 2:25:07 PM - user (192.168.2.12) > started uploading 'TPG.pdf' in 'D:\ftp\user\test\ftp\'.
(001517) 12/19/2009 2:25:07 PM - user (192.168.2.12) > 150 APPE supported. Ready to append file "TPG.pdf" at offset 202400.
(001517) 12/19/2009 2:25:08 PM - user (192.168.2.12) > 226 File received ok.
(001517) 12/19/2009 2:25:08 PM - user (192.168.2.12) > finished uploading 'TPG.pdf' in 'D:\ftp\user\test\ftp\' - (00:00:02 - 197.656 KB - 98.828 KBytes/s).

Сервер сначала шлёт сообщение с кодом 150, а потом 226, но cURL уже отфильтровал ответ и интерпретировал его как "предыдущая команда завершилась с ошибкой". После чего передача данных прекращается.

Анализ кода ответа FTP-сервера находится в файле ftp.c (исходный код библиотеки cURL). в районе строки 3342.

if(!ftpc->dont_check) {
/* 226 Transfer complete, 250 Requested file action okay, completed. */
if((ftpcode != 226) && (ftpcode != 250)) {
failf(data, "server did not report OK, got %d", ftpcode);
result = CURLE_PARTIAL_FILE;
}
}

Нехитрая правка в этом месте помогает решить проблему:

if(!ftpc->dont_check) {
/* Some ftp servers send double response, so if we get response code equal to 150 - try to get response again. */
if(ftpcode == 150))
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);

/* 226 Transfer complete, 250 Requested file action okay, completed. */
if((ftpcode != 226) && (ftpcode != 250)) {
failf(data, "server did not report OK, got %d", ftpcode);
result = CURLE_PARTIAL_FILE;
}
}

No comments: