URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID8
Нить номер: 3951
[ Назад ]

Исходное сообщение
"Траблы с stdin'ом (C++, Apache, Windows)"

Отправлено Павел , 09-Мрт-06 13:12 
Чес слово, искал везде, но ответа на вопрос не нашел :-( поэтому рискнул, ожидая ругательских выражений (типа "ну и какого??!! уже сто раз об этом говорили!!!"), написать сюда.

Итак, у меня Apache 2.0.53-win32, Windows XP SP2. Я хочу написать cgi-приложение на C++ (средство разработки - VS). Все бы хорошо, вот только библиотек нормальных не нашел (кстати, а встречается ли такое в природе?), поэтому решил поколупаться сам, тем более что форматы простые, разбираются без проблем. Ну и наткнулся на непреодолимое препятствие в виде баги (я так думаю, что это больше всего похоже на апачевскую багу, хотя, по отзывам выдавших мне в руки софт, у них в перловом скрипте такого не наблюдается).

Суть проблемы - из формы (enctype="multipart..." method = "post") клиент пытается выполнить передачу файла на сервер. Если файл короткий, проблем не возникает - читаю stdin (обычным read'ом, побайтно), разбираю его - все нормально. Но вот если он длинный (обычно траблы начинаются за пределами 64К) - получается индейское жилище. stdin просто оканчивается на 72К, без заключительных разделителей и прочего.

Пробовалось на файлах разной длины, разного наполнения (текстовые, исполняемые, картинки и т.д.). Поиски баги в сети ничего не дали, чаще всего люди глючат в смысле binmode (кстати, тоже интересный вопрос - ведь stdin, я так понимаю, в текстовом режиме открыт, кто как борется с этим делом?), в баглистах на apache.org че-то тоже ничего похожего не нашел...

Че ж делать-то? Может, я не сделал чего-то нужного с stdin'ом?

Могу и сырцы выложить, если кто интересуется и думает, что я просто глючный :-)


Содержание

Сообщения в этом обсуждении
"Траблы с stdin'ом (C++, Apache, Windows)"
Отправлено Павел , 10-Мрт-06 09:53 
Ну что, у кого есть идеи?

сырцы:

// типа проверка длины, test.c
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

int main()
{
int l = lseek(fileno(stdin),0,SEEK_END);
printf("Content-type: text/html\n\n");
printf("stdin length %d\n",l);
return 0;
}

// тестовая страничка
<FORM enctype="multipart/form-data" action="test.exe" method="post">
<input name="file" type="file"/>
</FORM>

Пытаюсь зафигачить файл длиной примерно 1 Мб (фотка)
// результат
stdin length 73536

Если вывести содержимое, получается типа:
----------------------id
Content-Disposition: name="file"; filename="(имя файла с путем на клиенте)"
Content-Type: (не помню уже)

(начало содержимого файла)
....
....

И все, почти стандартно на 73356 данные обрубаются. Почему "почти"? Потому что это иногда происходит на 8194, 65536 и прочих местах, я сначала думал, что глюки от последовательности в файле зависят - а фиг-то там, он один и тот же файл на разных местах оборвать может. Даже в логах нифига не пишется, как будто так и положено.

Я тут еще варианты придумал - может, дело в том, что у меня как-нибудь не так апач настроен? Хотя я его как поставил, не трогал, только каталог свой завел, безо всяких извратов...

В общем, даже проспавшись (уже в который раз :-)), я не решил вопрос... Вот еще попробую 2.0.55 поставить, может, будут изменения...


"Траблы не исчезли"
Отправлено Павел , 10-Мрт-06 14:10 
Попробовал я версию 2.0.55, траблы остались на месте... Мне теперь кажется, что бага не апачевская... Где-то что-то я не догоняю, это факт. Либо, как вариант, настройки операционки у меня какие-то не такие. Попробую на другой машине.

"Траблы не исчезли"
Отправлено Павел , 10-Мрт-06 14:59 
Пробы на другой машине дали аналогичный результат...
Недавно прочитал интересный текст (http://oreilly.jungles.ru/weblinux/cgi/ch03_01.htm):

3.1.1.1. STDIN
When a web server receives ...

!!! Note that there is no end-of-file marker, so if you try to read more data than is available, your CGI script will hang, waiting for more data on STDIN that will never come (eventually, the web server or browser should time out and kill this CGI script but this wastes system resources). !!!

... For POST requests, you should always refer to the value of the Content-Length header and read only that many bytes.

Короче, смысл-то вроде бы понятен, stdin в перлах (наверное, на юниксах) читается до тех пор, пока хочется, а дабы предохраниться от "втыкания" сервера, узнается CONTENT_LENGTH.

Но в моем случае не юниксы и не перл. STDIN имеет длину (может, это длина буфера?) и почему-то имеет "конец файла". Типа как-то надо дать понять драйверу, что я уже прочитал и надо бы следующий фрагментик в буфер кинуть... Вот только КАК?


"Траблы загнулись"
Отправлено Павел , 10-Мрт-06 17:40 
Короче, действительно, есть буфер stdin'а (кто бы сомневался :-)), и он обновляется по меоре чтения. И "конец файла" - на самом деле еще не конец :-).

Я сделал через API функции (GetStdHandle, ReadFile) - и, о счастье, все заработало! Даже FlushConsoleInputBuffer оказалсе ненужным. Просто надо читать подряд до тех пор, пока прочитанных байт возвращается не 0. Вот такие они, винды, ось со слабопредсказуемым поведением....