HTTP Content-Length неверный размер? - PullRequest
0 голосов
/ 09 августа 2010

Я передаю некоторые файлы локально через HTTP, используя QTcpSocket. Моя проблема в том, что только wget правильно загружает файл, Firefox добавляет в конец четыре дополнительных байта. Это заголовок, который я отправляю:

  HTTP/1.0 200 Ok
  Content-Length: 382917;
  Content-Type: application/x-shockwave-flash;
  Content-Disposition: attachment; filename=file.swf;

Этот код используется для отправки ответа:

        QTextStream os(socket);
        os.setAutoDetectUnicode(true);

        QString name = tokens[1].right(tokens[1].length() - 1);
        QString resname = ":/" + name; // the served file is a Qt resource
        QFile f(resname); f.open(QIODevice::ReadOnly);

        os << "HTTP/1.0 200 Ok\r\n" <<
              "Content-Length: " << f.size() << ";\r\n" <<
              "Content-Type: application/x-shockwave-flash;\r\n" <<
              "Content-Disposition: attachment; filename=" << name << 
              ";\r\n\r\n";

        os.flush();

        QDataStream ds(socket);

        ds << f.readAll();

        socket->close();

        if (socket->state() == QTcpSocket::UnconnectedState)
        {
            delete socket;
        }

Как я уже говорил выше, wget делает все правильно и загружает файл правильно. Проблема в том, что Firefox (и мое целевое приложение, экземпляр Flash ActiveX) этого не делают.

Четыре дополнительных байта всегда одинаковы: 4E E9 A5 F4

Шестнадцатеричный дамп http://www.freeimagehosting.net/uploads/a5711fd7af.gif

Мой вопрос: что я делаю неправильно, и что я должен изменить, чтобы сделать это правильно? Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 11 августа 2010

Итак, я нашел полное решение вопроса, и я думаю, что кому-то это может понадобиться, вот оно:

Первая проблема - это четыре лишних байта.Причина этого заключается в том, что согласно документации QDataStream"каждый элемент, записанный в поток, записывается в предопределенном двоичном формате, который варьируется в зависимости от типа элемента".И поскольку QFile.readAll() вернул QByteArray, QDataStream.operator<< записал этот объект в следующем формате:

  • Если байтовый массив равен нулю: 0xFFFFFFFF (quint32)
  • В противном случае:размер массива (quint32), за которым следуют байты массива, т.е. байты размера

( ссылка )

Итак, четыре дополнительных байта были четырьмя байтамиquint32, обозначающий размер массива.

Решение, согласно ответу janm, состояло в том, чтобы использовать функцию writeRawBytes().

QDataStream ds(socket);
ds.writeRawData(f.readAll().data(), f.size());

Wget, вероятно, сделал это правильно с первого раза, поскольку он строго соблюдаетполе Content-Length заголовка HTTP, в то время как, по-видимому, Firefox нет.

Вторая проблема заключалась в том, что, несмотря на правильный заголовок и рабочие гнезда, flashplayer не отображал желаемый контент вообще.Я экспериментировал с различными полями, чтобы он работал, и заметил, что при загрузке на реальный сервер все работает нормально.Я скопировал заголовок с сервера, и тадаа!оно работает.Это заголовок:

  HTTP/1.1 200 OK
  Server: Apache/2.2.15 (Fedora)
  Accept-Ranges: bytes
  Content-Length: 382917
  Content-Type: application/x-shockwave-flash
  Keep-Alive: timeout=15, max=100
  Connection: Keep-Alive

Сначала я только попытался установить версию 1.1, но это не помогло.Вероятно, это функция keepalive, но, честно говоря, мне все равно, пока она работает:).

1 голос
/ 09 августа 2010

Вы не должны заканчивать строки точкой с запятой.На первый взгляд это кажется наиболее вероятной проблемой.

Я не очень много знаю о QDataStream (или QT в целом), однако при быстром взгляде на документацию QDataStream упоминается оператор << (char const *).Если вы передаете строку с нулевым символом в конце в QDataStream, вы почти наверняка пройдете через конец последнего буфера. </p>

Попробуйте использовать QDataStream :: writeRawBytes ().

Если вы удалите точку с запятойтогда клиенты должны по крайней мере прочитать правильное количество байтов для ответа и игнорировать последние четыре байта.

Я бы тоже пропустил "Content-Disposition".Это вещь MIME, а не HTTP.

0 голосов
/ 09 августа 2010

В конце строки не должно быть точек с запятой.

...