]> git.saurik.com Git - apt-legacy.git/blobdiff - methods/http.cc
Fixed URLs with +'s not downloading from CDN.
[apt-legacy.git] / methods / http.cc
index 7e5bbc99b7c10da81a533627e021575ddfdbeee0..b512c5cb3fbe8c074c7300a30406695cca338b8e 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <apt-pkg/error.h>
 #include <apt-pkg/hashes.h>
 
+#include <sys/sysctl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <utime.h>
@@ -47,9 +48,11 @@ extern "C" {
 
 // Internet stuff
 #include <netdb.h>
+#include <arpa/inet.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <CoreServices/CoreServices.h>
+#include <SystemConfiguration/SystemConfiguration.h>
 
 #include "connect.h"
 #include "rfc2553emu.h"
@@ -58,6 +61,51 @@ extern "C" {
                                                                        /*}}}*/
 using namespace std;
 
+CFStringRef Firmware_;
+const char *Machine_;
+const char *SerialNumber_;
+
+void CfrsError(const char *name, CFReadStreamRef rs) {
+    CFStreamError se = CFReadStreamGetError(rs);
+
+    if (se.domain == kCFStreamErrorDomainCustom) {
+    } else if (se.domain == kCFStreamErrorDomainPOSIX) {
+        _error->Error("POSIX: %s", strerror(se.error));
+    } else if (se.domain == kCFStreamErrorDomainMacOSStatus) {
+        _error->Error("MacOSStatus: %ld", se.error);
+    } else if (se.domain == kCFStreamErrorDomainNetDB) {
+        _error->Error("NetDB: %s %s", name, gai_strerror(se.error));
+    } else if (se.domain == kCFStreamErrorDomainMach) {
+        _error->Error("Mach: %ld", se.error);
+    } else if (se.domain == kCFStreamErrorDomainHTTP) {
+        switch (se.error) {
+            case kCFStreamErrorHTTPParseFailure:
+                _error->Error("Parse failure");
+            break;
+
+            case kCFStreamErrorHTTPRedirectionLoop:
+                _error->Error("Redirection loop");
+            break;
+
+            case kCFStreamErrorHTTPBadURL:
+                _error->Error("Bad URL");
+            break;
+
+            default:
+                _error->Error("Unknown HTTP error: %ld", se.error);
+            break;
+        }
+    } else if (se.domain == kCFStreamErrorDomainSOCKS) {
+        _error->Error("SOCKS: %ld", se.error);
+    } else if (se.domain == kCFStreamErrorDomainSystemConfiguration) {
+        _error->Error("SystemConfiguration: %ld", se.error);
+    } else if (se.domain == kCFStreamErrorDomainSSL) {
+        _error->Error("SSL: %ld", se.error);
+    } else {
+        _error->Error("Domain #%ld: %ld", se.domain, se.error);
+    }
+}
+
 string HttpMethod::FailFile;
 int HttpMethod::FailFd = -1;
 time_t HttpMethod::FailTime = 0;
@@ -1072,7 +1120,22 @@ int HttpMethod::Loop()
 
       CFStringEncoding se = kCFStringEncodingUTF8;
 
-      CFStringRef sr = CFStringCreateWithCString(kCFAllocatorDefault, Queue->Uri.c_str(), se);
+      char *url = strdup(Queue->Uri.c_str());
+    url:
+      URI uri = std::string(url);
+      std::string hs = uri.Host;
+
+      std::string urs = uri;
+
+      for (;;) {
+         size_t bad = urs.find_first_of("+");
+         if (bad == std::string::npos)
+            break;
+         // XXX: generalize
+         urs = urs.substr(0, bad) + "%2b" + urs.substr(bad + 1);
+      }
+
+      CFStringRef sr = CFStringCreateWithCString(kCFAllocatorDefault, urs.c_str(), se);
       CFURLRef ur = CFURLCreateWithString(kCFAllocatorDefault, sr, NULL);
       CFRelease(sr);
       CFHTTPMessageRef hm = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), ur, kCFHTTPVersion1_1);
@@ -1088,37 +1151,81 @@ int HttpMethod::Loop()
          CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("If-Range"), sr);
          CFRelease(sr);
       } else if (Queue->LastModified != 0) {
-         sr = CFStringCreateWithCString(kCFAllocatorDefault, TimeRFC1123(SBuf.st_mtime).c_str(), se);
+         sr = CFStringCreateWithCString(kCFAllocatorDefault, TimeRFC1123(Queue->LastModified).c_str(), se);
          CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("If-Modified-Since"), sr);
          CFRelease(sr);
       }
 
+      if (Firmware_ != NULL)
+         CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("X-Firmware"), Firmware_);
+
+      sr = CFStringCreateWithCString(kCFAllocatorDefault, Machine_, se);
+      CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("X-Machine"), sr);
+      CFRelease(sr);
+
+      sr = CFStringCreateWithCString(kCFAllocatorDefault, SerialNumber_, se);
+      CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("X-Serial-Number"), sr);
+      CFRelease(sr);
+
       CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("User-Agent"), CFSTR("Telesphoreo APT-HTTP/1.0.98"));
+
       CFReadStreamRef rs = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, hm);
       CFRelease(hm);
 
-      CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
+      CFDictionaryRef dr = SCDynamicStoreCopyProxies(NULL);
+      CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPProxy, dr);
+      CFRelease(dr);
+
+      //CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
       CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
 
-      URI uri = Queue->Uri;
+      FetchResult Res;
+      CFIndex rd;
+      UInt32 sc;
+
+      uint8_t data[10240];
+      size_t offset = 0;
 
-      Status("Connecting to %s", uri.Host.c_str());
+      Status("Connecting to %s", hs.c_str());
 
       if (!CFReadStreamOpen(rs)) {
+         CfrsError("Open", rs);
          Fail(true);
-         continue;
+         goto done;
       }
 
-      uint8_t data[10240];
-      CFIndex rd = CFReadStreamRead(rs, data, sizeof(data));
+      rd = CFReadStreamRead(rs, data, sizeof(data));
+
+      if (rd == -1) {
+         CfrsError(uri.Host.c_str(), rs);
+         Fail(true);
+         goto done;
+      }
 
-      FetchResult Res;
       Res.Filename = Queue->DestFile;
 
       hm = (CFHTTPMessageRef) CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader);
-      UInt32 sc = CFHTTPMessageGetResponseStatusCode(hm);
+      sc = CFHTTPMessageGetResponseStatusCode(hm);
 
-      size_t offset = 0;
+      if (sc == 301 || sc == 302) {
+         sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Location"));
+         if (sr == NULL) {
+            Fail();
+            goto done_;
+         } else {
+            size_t ln = CFStringGetLength(sr) + 1;
+            free(url);
+            url = static_cast<char *>(malloc(ln));
+
+            if (!CFStringGetCString(sr, url, ln, se)) {
+               Fail();
+               goto done_;
+            }
+
+            CFRelease(sr);
+            goto url;
+         }
+      }
 
       sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Content-Range"));
       if (sr != NULL) {
@@ -1127,7 +1234,7 @@ int HttpMethod::Loop()
 
          if (!CFStringGetCString(sr, cr, ln, se)) {
             Fail();
-            goto done;
+            goto done_;
          }
 
          CFRelease(sr);
@@ -1135,13 +1242,13 @@ int HttpMethod::Loop()
          if (sscanf(cr, "bytes %lu-%*u/%lu", &offset, &Res.Size) != 2) {
            _error->Error(_("The HTTP server sent an invalid Content-Range header"));
             Fail();
-            goto done;
+            goto done_;
          }
 
          if (offset > Res.Size) {
            _error->Error(_("This HTTP server has broken range support"));
             Fail();
-            goto done;
+            goto done_;
          }
       } else {
          sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Content-Length"));
@@ -1160,7 +1267,7 @@ int HttpMethod::Loop()
 
          if (!CFStringGetCString(sr, cr, ln, se)) {
             Fail();
-            goto done;
+            goto done_;
          }
 
          CFRelease(sr);
@@ -1168,7 +1275,7 @@ int HttpMethod::Loop()
          if (!StrToTime(cr, Res.LastModified)) {
            _error->Error(_("Unknown date format"));
             Fail();
-            goto done;
+            goto done_;
          }
       }
 
@@ -1215,9 +1322,10 @@ int HttpMethod::Loop()
 
         URIStart(Res);
 
-         read: if (rd == -1)
+         read: if (rd == -1) {
+            CfrsError("rd", rs);
             Fail(true);
-         else if (rd == 0) {
+         else if (rd == 0) {
            if (Res.Size == 0)
               Res.Size = File->Size();
 
@@ -1252,8 +1360,13 @@ int HttpMethod::Loop()
          }
       }
 
+     goto done;
+    done_:
+      CFRelease(hm);
     done:
+      CFReadStreamClose(rs);
       CFRelease(rs);
+      free(url);
 
       FailCounter = 0;
    }
@@ -1264,16 +1377,51 @@ int HttpMethod::Loop()
 
 int main()
 {
+#if !defined(__ENVIRONMENT_ASPEN_VERSION_MIN_REQUIRED__) || __ENVIRONMENT_ASPEN_VERSION_MIN_REQUIRED__ < 10200
    struct nlist nl[2];
    memset(nl, 0, sizeof(nl));
-   nl[0].n_un.n_name = "_useMDNSResponder";
+   nl[0].n_un.n_name = (char *) "_useMDNSResponder";
    nlist("/usr/lib/libc.dylib", nl);
    if (nl[0].n_type != N_UNDF)
        *(int *) nl[0].n_value = 0;
+#endif
 
    setlocale(LC_ALL, "");
 
    HttpMethod Mth;
+
+    size_t size;
+    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+    char *machine = new char[size];
+    sysctlbyname("hw.machine", machine, &size, NULL, 0);
+    Machine_ = machine;
+
+    const char *path = "/System/Library/CoreServices/SystemVersion.plist";
+    CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (uint8_t *) path, strlen(path), false);
+
+    CFPropertyListRef plist; {
+        CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
+        CFReadStreamOpen(stream);
+        plist = CFPropertyListCreateFromStream(kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL, NULL);
+        CFReadStreamClose(stream);
+    }
+
+    CFRelease(url);
+
+    if (plist != NULL) {
+        Firmware_ = (CFStringRef) CFRetain(CFDictionaryGetValue((CFDictionaryRef) plist, CFSTR("ProductVersion")));
+        CFRelease(plist);
+    }
+
+    if (CFMutableDictionaryRef dict = IOServiceMatching("IOPlatformExpertDevice"))
+        if (io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, dict)) {
+            if (CFTypeRef serial = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0)) {
+                SerialNumber_ = strdup(CFStringGetCStringPtr((CFStringRef) serial, CFStringGetSystemEncoding()));
+                CFRelease(serial);
+            }
+
+            IOObjectRelease(service);
+        }
    
    return Mth.Loop();
 }