]> git.saurik.com Git - apple/security.git/blobdiff - Network/http-protocol.cpp
Security-54.1.tar.gz
[apple/security.git] / Network / http-protocol.cpp
index 814d911e1d7c0b2b4be0f29a8f0b6239993215d9..6a94d92fbe663482e8e63866c7b831f63214b434 100644 (file)
@@ -72,6 +72,7 @@ HTTPProtocol::HTTPTransfer *HTTPProtocol::makeTransfer(const Target &target, Ope
 HTTPProtocol::HTTPConnection::HTTPConnection(Protocol &proto,
     const HostTarget &hostTarget)
     : TCPConnection(proto, hostTarget),
 HTTPProtocol::HTTPConnection::HTTPConnection(Protocol &proto,
     const HostTarget &hostTarget)
     : TCPConnection(proto, hostTarget),
+    subVersion(defaultSubVersion),
     state(errorState), deferSendRequest(false)
 {
     const HostTarget &host = proxyHostTarget();
     state(errorState), deferSendRequest(false)
 {
     const HostTarget &host = proxyHostTarget();
@@ -96,15 +97,17 @@ void HTTPProtocol::HTTPConnection::sendRequest()
 {
     assert(state == idle);
 
 {
     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()) {
     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 {
         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,
     }
     hostHeader();
     authorizationHeader("Authorization", target,
@@ -144,6 +147,7 @@ void HTTPProtocol::HTTPConnection::sendRequest()
         } else {
             printfe("Content-length: %ld", size);
         }
         } 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 {
         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 **");
             } 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")) {
                 
                 // 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
                     }
                 }
                 // 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);
                 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());
                 }
                     mode(sink());
                 }
-                state = readWholeBody;
             }
             break;
         }
             }
             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",
         {
             // 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;
         }
             abort();
             state = dead;
         }
@@ -373,10 +381,11 @@ void HTTPProtocol::HTTPConnection::transitError(const CssmCommonError &error)
 
 void HTTPProtocol::HTTPConnection::finish()
 {
 
 void HTTPProtocol::HTTPConnection::finish()
 {
+    flushInput();                      // clear excess garbage input (resynchronize)
     chooseRetain();                    // shall we keep the Connection?
     chooseRetain();                    // shall we keep the Connection?
-    Connection::finish();      // finish this transfer
     mode(lineInput);           // ensure valid input mode
     state = idle;                      // idle state
     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()
 {
 
 void HTTPProtocol::HTTPTransfer::abort()
 {
+    observe(Observer::aborting);
     setError("aborted");
     connectionAs<HTTPConnection>().abort();
 }
     setError("aborted");
     connectionAs<HTTPConnection>().abort();
 }
@@ -476,8 +486,10 @@ Transfer::ResultClass HTTPProtocol::HTTPTransfer::resultClass() const
             if (mResultClass != unclassifiedFailure)
                 return mResultClass;   // preclassified
             unsigned int code = httpResponseCode();
             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;
                 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 :-)
             else if (code / 100 == 2)                  // success codes
                 return success;
             else       // when in doubt, blame the remote end :-)