Working with Buffered streams
Bradley Smith
digitalmars-com at baysmith.com
Fri Apr 6 10:35:30 PDT 2007
There is a bug in the Stream class. If you mix, readLine() and
read(ubyte[]) calls to a stream, readLine() may not appear to perform as
documented. As documented, readLine() stop at "some combination of
carriage return [CR] and line feed [LF]". However, this is not
necessarily true. If the stream is non-seekable, readLine() will stop at
CR and set a prevCr flag indicating that a LF should be consumed on the
next read. However, this only takes place in the getc() method and
methods using getc(). Some methods, like read(ubyte[]), read the stream
directly and the prevCr flag is not processed.
At first, I thought this might just be odd behavior rather than a bug,
but I decided that it is a bug. In order to understand how to use the
stream effectively, one must understand the implementation details. One
must know that the behavior for seekable streams is different that
non-seekable streams, and adjust the client code accordingly. For this
reason, it should be considered a bug.
The workaround this bug is to check the first character of a
non-seekable stream after reading with readLine(). For example:
if(!ss.seekable) {
ss.read(b);
if (b[0] != '\n') {
s.write(b);
}
}
while(ss.read(b) != 0){
s.write(b);
}
Thanks,
Bradley
Lorenzo Villani wrote:
> Ok, this is a very noob-ish question :)
>
> I'm writing a simple HTTP file downloader (you can find it attached to this post) but I have some troubles getting a proper file after transfer. (eg: local downloaded file is corrupted). Can someone help me? (Please note that i'm new to this language :D )
>
>
> ------------------------------------------------------------------------
>
> import std.file;
> import std.string;
> import std.stdio;
> import std.stream;
> import std.socketstream;
> import std.socket;
>
> class HttpDownload {
> public:
> this() {}
>
> void downloadFile(char[] domain, char[] dir, char[] file, int port = 80) {
> Socket sock = new TcpSocket(new InternetAddress(domain, port));
> SocketStream ss = new SocketStream(sock);
>
> // we prepare the request
> if ( port != 80 )
> domain = domain ~ ":" ~ cast(char)port;
>
> char[] request = "GET " ~ dir ~ "/" ~ file ~ " HTTP/1.1\r\n"
> ~ "Connection: Keep-Alive\r\n"
> ~ "User-Agent: Mozilla 5.0\r\n"
> ~ "Host: " ~ domain ~ "\r\n"
> ~ "\r\n";
>
> // we send the request
> ss.writeString(request);
>
> // this for removes the HTTP header and looks for a positive response
> // from the webserver
> for(;;) {
> char[] response = ss.readLine();
> char[] RESPONSE = "HTTP/1.1 ";
>
> if(!response.length) {
> break;
> } else {
> if (response.length > RESPONSE.length && !icmp(RESPONSE, response[0 .. RESPONSE.length])) {
> char[] code;
> code = response[RESPONSE.length .. response.length];
> int i = ifind(code, "200 OK");
> if ( i != -1 ) {
> writefln("---> Received a 200 OK");
> } else {
> throw new Exception("Webserver has replied with an error");
> return;
> }
> }
> }
> }
>
> // write file
> BufferedFile s = new BufferedFile();
> s.create(getcwd() ~ "/" ~ file);
> ubyte[1] b;
> while(ss.read(b) != 0){
> s.write(b);
> }
> ss.close();
> s.close();
> }
> }
>
> int main() {
> HttpDownload download = new HttpDownload();
> download.downloadFile("www.capponcino.it", "/tremulous/dl/pk3", "highrise-b4.pk3", 80);
> return 0;
> }
More information about the Digitalmars-d-learn
mailing list