HTTPProtocol::HTTPConnection::HTTPConnection(Protocol &proto,
const HostTarget &hostTarget)
: TCPConnection(proto, hostTarget),
+ subVersion(defaultSubVersion),
state(errorState), deferSendRequest(false)
{
const HostTarget &host = proxyHostTarget();
{
assert(state == idle);
+ // what version of HTTP/1 shall we use?
+ subVersion = getv<int>(kNetworkHttpUseVersion, defaultSubVersion);
+
flushOutput(false); // hold output until we're done
const Target &target = this->target();
if (transfer().useProxyHeaders()) {
- printfe("%s %s HTTP/1.1",
- mOperation.c_str(), target.urlForm().c_str());
+ printfe("%s %s HTTP/1.%d", mOperation.c_str(), target.urlForm().c_str(), subVersion);
authorizationHeader("Proxy-Authorization", hostTarget,
kNetworkGenericProxyUsername, kNetworkGenericProxyPassword);
} else {
- printfe("%s %s HTTP/1.1", mOperation.c_str(), target.path.c_str());
+ printfe("%s %s HTTP/1.%d", mOperation.c_str(), target.path.c_str(), subVersion);
}
hostHeader();
authorizationHeader("Authorization", target,
} else {
printfe("Content-length: %ld", size);
}
+ printfe("Content-Type: %s", getv<string>(kNetworkHttpPostContentType, "text/plain").c_str());
printfe(""); // end of headers
mode(source); // initiate autoWrite mode
} else {
} else { // end of headers
// we are now handling the transition from response headers to response body
observe(Observer::protocolReceive, "** END OF HEADER **");
+ observe(Observer::downloading, input);
// Transfer-Encoding overrides Content-Length as per RFC2616 p.34
if (const char *encoding = headers().find("Transfer-Encoding")) {
}
}
// 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
}
void HTTPProtocol::HTTPTransfer::abort()
{
+ observe(Observer::aborting);
setError("aborted");
connectionAs<HTTPConnection>().abort();
}
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 :-)