X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/bac41a7b9a0a9254fa30f8bb6e6038ab71a483e2..67c7378dcb8de24c86b7fedff90b4b496f2e474c:/Network/http-protocol.cpp diff --git a/Network/http-protocol.cpp b/Network/http-protocol.cpp index 814d911e..6a94d92f 100644 --- a/Network/http-protocol.cpp +++ b/Network/http-protocol.cpp @@ -72,6 +72,7 @@ HTTPProtocol::HTTPTransfer *HTTPProtocol::makeTransfer(const Target &target, Ope HTTPProtocol::HTTPConnection::HTTPConnection(Protocol &proto, const HostTarget &hostTarget) : TCPConnection(proto, hostTarget), + subVersion(defaultSubVersion), state(errorState), deferSendRequest(false) { const HostTarget &host = proxyHostTarget(); @@ -96,15 +97,17 @@ void HTTPProtocol::HTTPConnection::sendRequest() { assert(state == idle); + // what version of HTTP/1 shall we use? + subVersion = getv(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, @@ -144,6 +147,7 @@ void HTTPProtocol::HTTPConnection::sendRequest() } else { printfe("Content-length: %ld", size); } + printfe("Content-Type: %s", getv(kNetworkHttpPostContentType, "text/plain").c_str()); printfe(""); // end of headers mode(source); // initiate autoWrite mode } else { @@ -274,6 +278,7 @@ void HTTPProtocol::HTTPConnection::transit(Event event, char *input, size_t leng } 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")) { @@ -290,14 +295,17 @@ void HTTPProtocol::HTTPConnection::transit(Event event, char *input, size_t leng } } // 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; } @@ -354,7 +362,7 @@ void HTTPProtocol::HTTPConnection::transit(Event event, char *input, size_t leng { // 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; } @@ -373,10 +381,11 @@ void HTTPProtocol::HTTPConnection::transitError(const CssmCommonError &error) 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 } @@ -430,6 +439,7 @@ void HTTPProtocol::HTTPTransfer::start() void HTTPProtocol::HTTPTransfer::abort() { + observe(Observer::aborting); setError("aborted"); connectionAs().abort(); } @@ -476,8 +486,10 @@ Transfer::ResultClass HTTPProtocol::HTTPTransfer::resultClass() const 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 :-)