diff -ru apt-0.6.46.4.1/methods/http.cc apt-0.6.46.4.1+iPhone/methods/http.cc --- apt-0.6.46.4.1/methods/http.cc 2006-12-04 14:37:36.000000000 +0000 +++ apt-0.6.46.4.1+iPhone/methods/http.cc 2008-05-11 06:33:29.000000000 +0000 @@ -30,6 +34,7 @@ #include #include +#include #include #include #include @@ -43,6 +48,11 @@ // Internet stuff #include +#include + +#include +#include +#include #include "connect.h" #include "rfc2553emu.h" @@ -51,6 +61,51 @@ /*}}}*/ 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; @@ -1062,159 +1117,257 @@ if (Queue == 0) continue; - - // Connect to the server - if (Server == 0 || Server->Comp(Queue->Uri) == false) - { - delete Server; - Server = new ServerState(Queue->Uri,this); - } - - /* If the server has explicitly said this is the last connection - then we pre-emptively shut down the pipeline and tear down - the connection. This will speed up HTTP/1.0 servers a tad - since we don't have to wait for the close sequence to - complete */ - if (Server->Persistent == false) - Server->Close(); - - // Reset the pipeline - if (Server->ServerFd == -1) - QueueBack = Queue; - - // Connnect to the host - if (Server->Open() == false) - { - Fail(true); - delete Server; - Server = 0; - continue; - } - // Fill the pipeline. - Fetch(0); - - // Fetch the next URL header data from the server. - switch (Server->RunHeaders()) - { - case 0: - break; - - // The header data is bad - case 2: - { - _error->Error(_("Bad header data")); - Fail(true); - RotateDNS(); - continue; - } - - // The server closed a connection during the header get.. - default: - case 1: - { - FailCounter++; - _error->Discard(); - Server->Close(); - Server->Pipeline = false; - - if (FailCounter >= 2) - { - Fail(_("Connection failed"),true); - FailCounter = 0; - } - - RotateDNS(); - continue; - } - }; + CFStringEncoding se = kCFStringEncodingUTF8; + + 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); + CFRelease(ur); + + struct stat SBuf; + if (stat(Queue->DestFile.c_str(), &SBuf) >= 0 && SBuf.st_size > 0) { + sr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("bytes=%li-"), (long) SBuf.st_size - 1); + CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("Range"), sr); + CFRelease(sr); + + sr = CFStringCreateWithCString(kCFAllocatorDefault, TimeRFC1123(SBuf.st_mtime).c_str(), se); + CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("If-Range"), sr); + CFRelease(sr); + } else if (Queue->LastModified != 0) { + 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); + + CFDictionaryRef dr = SCDynamicStoreCopyProxies(NULL); + CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPProxy, dr); + CFRelease(dr); + + //CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue); + CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); - // Decide what to do. FetchResult Res; + CFIndex rd; + UInt32 sc; + + uint8_t data[10240]; + size_t offset = 0; + + Status("Connecting to %s", hs.c_str()); + + if (!CFReadStreamOpen(rs)) { + CfrsError("Open", rs); + Fail(true); + goto done; + } + + rd = CFReadStreamRead(rs, data, sizeof(data)); + + if (rd == -1) { + CfrsError(uri.Host.c_str(), rs); + Fail(true); + goto done; + } + Res.Filename = Queue->DestFile; - switch (DealWithHeaders(Res,Server)) - { - // Ok, the file is Open - case 0: - { - URIStart(Res); - // Run the data - bool Result = Server->RunData(); + hm = (CFHTTPMessageRef) CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader); + sc = CFHTTPMessageGetResponseStatusCode(hm); - /* If the server is sending back sizeless responses then fill in - the size now */ + 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(malloc(ln)); + + if (!CFStringGetCString(sr, url, ln, se)) { + Fail(); + goto done_; + } + + CFRelease(sr); + goto url; + } + } + + sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Content-Range")); + if (sr != NULL) { + size_t ln = CFStringGetLength(sr) + 1; + char cr[ln]; + + if (!CFStringGetCString(sr, cr, ln, se)) { + Fail(); + goto done_; + } + + CFRelease(sr); + + 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_; + } + + if (offset > Res.Size) { + _error->Error(_("This HTTP server has broken range support")); + Fail(); + goto done_; + } + } else { + sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Content-Length")); + if (sr != NULL) { + Res.Size = CFStringGetIntValue(sr); + CFRelease(sr); + } + } + + time(&Res.LastModified); + + sr = CFHTTPMessageCopyHeaderFieldValue(hm, CFSTR("Last-Modified")); + if (sr != NULL) { + size_t ln = CFStringGetLength(sr) + 1; + char cr[ln]; + + if (!CFStringGetCString(sr, cr, ln, se)) { + Fail(); + goto done_; + } + + CFRelease(sr); + + if (!StrToTime(cr, Res.LastModified)) { + _error->Error(_("Unknown date format")); + Fail(); + goto done_; + } + } + + CFRelease(hm); + + if (sc == 304) { + unlink(Queue->DestFile.c_str()); + Res.IMSHit = true; + Res.LastModified = Queue->LastModified; + URIDone(Res); + } else if (sc < 200 || sc >= 300) + Fail(); + else { + Hashes hash; + + File = new FileFd(Queue->DestFile, FileFd::WriteAny); + if (_error->PendingError() == true) { + delete File; + File = NULL; + Fail(); + goto done; + } + + FailFile = Queue->DestFile; + FailFile.c_str(); // Make sure we dont do a malloc in the signal handler + FailFd = File->Fd(); + FailTime = Res.LastModified; + + Res.ResumePoint = offset; + ftruncate(File->Fd(), offset); + + if (offset != 0) { + lseek(File->Fd(), 0, SEEK_SET); + if (!hash.AddFD(File->Fd(), offset)) { + _error->Errno("read", _("Problem hashing file")); + delete File; + File = NULL; + Fail(); + goto done; + } + } + + lseek(File->Fd(), 0, SEEK_END); + + URIStart(Res); + + read: if (rd == -1) { + CfrsError("rd", rs); + Fail(true); + } else if (rd == 0) { if (Res.Size == 0) Res.Size = File->Size(); - - // Close the file, destroy the FD object and timestamp it - FailFd = -1; - delete File; - File = 0; - - // Timestamp + struct utimbuf UBuf; time(&UBuf.actime); - UBuf.actime = Server->Date; - UBuf.modtime = Server->Date; - utime(Queue->DestFile.c_str(),&UBuf); + UBuf.actime = Res.LastModified; + UBuf.modtime = Res.LastModified; + utime(Queue->DestFile.c_str(), &UBuf); - // Send status to APT - if (Result == true) - { - Res.TakeHashes(*Server->In.Hash); - URIDone(Res); - } - else - Fail(true); - - break; - } - - // IMS hit - case 1: - { + Res.TakeHashes(hash); URIDone(Res); - break; - } - - // Hard server error, not found or something - case 3: - { - Fail(); - break; - } - - // Hard internal error, kill the connection and fail - case 5: - { - delete File; - File = 0; + } else { + hash.Add(data, rd); - Fail(); - RotateDNS(); - Server->Close(); - break; - } + uint8_t *dt = data; + while (rd != 0) { + int sz = write(File->Fd(), dt, rd); + + if (sz == -1) { + delete File; + File = NULL; + Fail(); + goto done; + } + + dt += sz; + rd -= sz; + } + + rd = CFReadStreamRead(rs, data, sizeof(data)); + goto read; + } + } + + goto done; + done_: + CFRelease(hm); + done: + CFReadStreamClose(rs); + CFRelease(rs); + free(url); - // We need to flush the data, the header is like a 404 w/ error text - case 4: - { - Fail(); - - // Send to content to dev/null - File = new FileFd("/dev/null",FileFd::WriteExists); - Server->RunData(); - delete File; - File = 0; - break; - } - - default: - Fail(_("Internal error")); - break; - } - FailCounter = 0; } @@ -1224,6 +1386,39 @@ 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(); } diff -ru apt-0.6.46.4.1/methods/makefile apt-0.6.46.4.1+iPhone/methods/makefile --- apt-0.6.46.4.1/methods/makefile 2006-12-04 14:37:36.000000000 +0000 +++ apt-0.6.46.4.1+iPhone/methods/makefile 2008-05-11 06:32:33.000000000 +0000 @@ -47,7 +47,7 @@ # The http method PROGRAM=http -SLIBS = -lapt-pkg $(SOCKETLIBS) +SLIBS = -lapt-pkg $(SOCKETLIBS) -framework CoreFoundation -framework CFNetwork -framework SystemConfiguration -framework IOKit LIB_MAKES = apt-pkg/makefile SOURCE = http.cc rfc2553emu.cc connect.cc include $(PROGRAM_H)