}
}
// no transfer-encoding (or transfer-encoding: identity): big gulp mode
+ state = readWholeBody;
if (const char *lengthArg = headers().find("Content-Length")) {
size_t length = strtol(lengthArg, NULL, 10);
sink().setSize(length);
- mode(sink(), length);
- } else {
+ if (length > 0)
+ mode(sink(), length);
+ else // null body, already done
+ finish();
+ } else { // read until EOI
mode(sink());
}
- state = readWholeBody;
}
break;
}
{
// the only asynchronous event in idle mode is a connection drop
debug("http",
- "event %d while idle; destroying connection", event);
+ "%p event %d while idle; destroying connection", this, event);
abort();
state = dead;
}
void HTTPProtocol::HTTPConnection::finish()
{
+ flushInput(); // clear excess garbage input (resynchronize)
chooseRetain(); // shall we keep the Connection?
- Connection::finish(); // finish this transfer
mode(lineInput); // ensure valid input mode
state = idle; // idle state
+ Connection::finish(); // finish this transfer
}
if (mResultClass != unclassifiedFailure)
return mResultClass; // preclassified
unsigned int code = httpResponseCode();
- if (code == 401 || code == 407) // auth or proxy auth required
+ if (code == 401 || code == 407 || code == 305) // auth or proxy auth required
return authorizationFailure;
+ else if (code / 100 == 3) // redirect (interpreted as success)
+ return success;
else if (code / 100 == 2) // success codes
return success;
else // when in doubt, blame the remote end :-)
}
+//
+// Discard any data still in the input buffer.
+// This is used to cope with unexpected garbage (protocol violations
+// from the server), and shouldn't be used indiscriminately.
+//
+void TransferEngine::Client::flushInput()
+{
+ if (!mReadBuffer.isEmpty()) {
+ debug("engineio", "flushing %ld bytes of input", mReadBuffer.length());
+ mReadBuffer.clear();
+ mInputFlushed = true; // inhibit normal buffer ops
+ }
+}
+
+
//
// Given that autoCopyOut mode is active, try to transfer some bytes
// into the write buffer. This is a lazy, fast push, suitable for tacking on
this, fd, io.iocget<int>(FIONREAD)));
do {
+ mInputFlushed = false; // preset normal
+
//@@@ break out after partial buffer to give Equal Time to other transfers? good idea?!
- if (mReadBuffer.read(*this) == 0) {
+ if (!atEnd() && mReadBuffer.read(*this) == 0 && !atEnd()) {
mReadBuffer.read(*this, true);
}
rawInputTransit();
break;
case lineInput:
- lineInputTransit();
+ if (!lineInputTransit())
+ return; // no full line; try again later
break;
case autoReadInput:
autoReadInputTransit();
assert(false);
}
if (!io) // client has unhooked; clear buffer and exit loop
- mReadBuffer.clear();
+ flushInput();
} while (!mReadBuffer.isEmpty());
//@@@ feed back for more output here? But also see comments above...
//@@@ probably better to take the trip through the Selector
IFDEBUG(debug("engineio", "%p(%d) --> %d bytes RAW",
this, fileDesc(), io.iocget<int>(FIONREAD)));
transit(inputAvailable, addr, length);
- mReadBuffer.usePut(length);
+ if (!mInputFlushed)
+ mReadBuffer.useGet(length);
}
-void TransferEngine::Client::lineInputTransit()
+bool TransferEngine::Client::lineInputTransit()
{
char *line; size_t length = mReadBuffer.length();
mReadBuffer.locateGet(line, length);
char *nl;
for (nl = line; nl < line + length && *nl != '\n'; nl++) ;
if (nl == line + length) // no end-of-line, wait for more
- return;
+ return false;
if (nl > line && nl[-1] == '\r') { // proper \r\n termination
nl[-1] = '\0'; // terminate for transit convenience
debug("engineio", "%p(%d) [IMPROPER] --> %s", this, fileDesc(), line);
transit(inputAvailable, line, nl - line);
}
- mReadBuffer.useGet(nl - line + 1);
+ if (!mInputFlushed)
+ mReadBuffer.useGet(nl - line + 1);
+ return true;
}
void TransferEngine::Client::autoReadInputTransit()
mReadBuffer.locateGet(data, length);
debug("engineio", "%p(%d) --> %ld bytes autoReadInput", this, fileDesc(), length);
mSink->consume(data, length);
- mReadBuffer.useGet(length);
+ if (!mInputFlushed)
+ mReadBuffer.useGet(length);
if (mResidualReadCount && (mResidualReadCount -= length) == 0)
mMode = autoIODone;
}