HTBlackHole problem & dealing with stream return codes in HTTee
To: "'Henrik Frystyk Nielsen'" <firstname.lastname@example.org>
Subject: HTBlackHole problem & dealing with stream return codes in HTTee
From: Maciej Puzio <email@example.com>
Date: Wed, 20 Dec 1995 14:56:13 +-100
Cc: "'WWW Library Mailing List'" <firstname.lastname@example.org>
From email@example.com Wed Dec 20 08: 59:23 1995
I have a few words about the HTBlackHole stream (HTFWrite.c). It is undoubtly the
simplest thing in the library, however I have managed to find one problem connected
with it :-) .
The theory with the HTBlackHole is that it just absorbs data and returns HT_OK. This
stream is used in the library as a "working" NULL in all functions returning streams.
That is, if some error occurs and the function can't return the appropriate stream, it
returns HTBlackHole instead.
This works perfectly in theory, but not in practice, I'm afraid. Here's the example (taken
from the real life) showing that this behavior can cause strange and confusing results.
In a simple WWW browser I have written using the WWWLib the user clicks on the
link (anchor) leading to the ZIP file. After a while, the beautiful dialog box appears
prompting for the file name (the ZIP files are not presented to the user, they are saved
to the disk instead). The user enters the name and clicks OK, and then watches
the "Reading (2% of 3.8M)" messages for a while (sometimes a long one). After
that the file is saved on the local disk. That's perfectly OK, but what happens if the
user clicks Cancel button in the dialog box? The file is not saved to the disk, but the
message "Reading (2% of 3.8M)" still appears and changes slowly from 1% to 100%.
This really can lead to a deep confusion...
Why's that? The library creates a stream stack to deal with the transmitted data body
after parsing the MIME headers. In our example, the body is in the ZIP format, so the
library decides that it should be saved to the disk (see HTConverterInit() in HTInit.c).
It constructs then a HTSaveLocally stream using HTSaveLocally() function
(HTFWrite.c). This function prompts the user for a file name (via HTAlert). If it gets
NULL (which means an error, e.g. click on Cancel button), the HTBlackHole is returned
to the HTSaveLocally() caller. And instead of cancelling the connection, the data keeps
flowing from the network and getting to the HTBlackHole, where it's discarded.
The easiest solution is to change the result codes returned in
HTBlackHole_put_character, HTBlackHole_put_string and HTBlackHole_write
from HT_OK to HT_ERROR. This immediately stops receiving the data. There is
however one VERY serious drawback. If the HTBlackHole is the main output stream,
everything is all right, but what if not? What if HTBlackHole is used in place of some
stream of a secondary importance (cache for example), attached to the main stream
with a HTTee? Here we meet the problem we were discussing a few days ago: how
the stream return codes should propagate in HTTee? (To Henrik: sorry I haven't
answered your last letter until now, but I had to think about the problem).
> We can either say that this is a problem with a T stream or change the status
> code numbers and use bitflags instead. Error codes can still be negative by
> haing the MSB set to 1. This way you can easily check for error/success _and_
> at the same time return multiple return codes. Does anybody see a problem with
> this except that you need to use binary operations on the return values?
Here's the problem: bitflags won't allow you to indicate the importance of each return
1. The HTBlackHole should return some special code, e.g. HT_STOP_BLACKHOLE.
This would cause the whole engine to stop, but would not propagate in HTTee (unless
two streams return this).
2. Who knows what the importance of a stream is? The function which created it,
of course. So, the function which creates HTTee and then attaches two streams
to it should pass HTTee a special callback function as a parameter. This callback
function would be used for resolving the stream return codes conflicts. To ease
programming, HTTee should have a default resolving function, something similar to
merge_results in Hakon's version.
That's all for now. I would appreciate any opinions and further discussion.