I'm serving some files locally via HTTP using QTcpSocket. My problem is that only wget downloads the file properly, firefox adds four extra bytes to the end. This is the header I send:
HTTP/1.0 200 Ok
Content-Length: 382917;
Content-Type: application/x-shockwave-flash;
Content-Disposition: attachment; filename=file.swf;
This is the code used to send the response:
QTextStream os(socket);
os.setAutoDetectUnicode(true);
QString name = tokens[1].right(tokens[1].length() - 1);
QString res开发者_如何学运维name = ":/" + 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;
}
As I stated above, wget gets it right and downloads the file properly. The problem is that Firefox (and my target application, a Flash ActiveX instance) don't.
The four extra bytes are always the same: 4E E9 A5 F4
Hex dump http://www.freeimagehosting.net/uploads/a5711fd7af.gif
My question is what am I doing wrong, and what should I change to get it right? Thanks in advance.
You should not be terminating the lines with semicolons. At first glance this seems like the most likely problem.
I don't know much about QDataStream (or QT in general), however a quick look at the QDataStream documentation mentions operator<<(char const*). If you are passing a null terminated string to QDataStream, you are almost certainly going over the end of the final buffer.
Try using QDataStream::writeRawBytes().
If you remove the semicolons, then the clients should at least read the correct number of bytes for the response and ignore the last four bytes.
I'd leave out "Content-Disposition" too. That's a MIME thing, not an HTTP thing.
So I found the whole solution to the question, and I think someone might need it, so here it is:
The first problem were the four extra bytes. The reason for this is that according to the QDataStream documentation, "each item written to the stream is written in a predefined binary format that varies depending on the item's type". And as QFile.readAll()
returned a QByteArray
, QDataStream.operator<<
wrote that object in the following format:
- If the byte array is null: 0xFFFFFFFF (quint32)
- Otherwise: the array size (quint32) followed by the array bytes, i.e. size bytes
(link)
So, the four extra bytes were the four bytes of quint32 that denoted the array size.
The solution, according to janm's answer was to use the writeRawBytes()
function.
QDataStream ds(socket);
ds.writeRawData(f.readAll().data(), f.size());
Wget probably got it right the first time because it strictly enforces the Content-Length
field of the HTTP header, while apparently firefox does not.
The second problem was that despite the right header and working sockets, the flashplayer did not display the desired content at all. I experimented with various fields to make it work, and noticed that by uploading to a real server, it works all right. I copied the header from server, and tadaa! it works. This is the header:
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
At first I only tried setting the version to 1.1, but that didn't help. Probably it's the keepalive thing, but honestly, I don't care at all as long as it works :).
There shouldn't be any semicolons at the end of the line.
精彩评论