From 5588ad4211e346be5fcbad966effb02361c84272 Mon Sep 17 00:00:00 2001 From: Jay Freeman Date: Mon, 25 Feb 2008 10:38:40 +0000 Subject: Rewrote APT's HTTP method to use CFNetwork in order to handle transparent proxy caches, temporary/permanent redirects, and proxy auto-configuration urls. git-svn-id: http://svn.telesphoreo.org/trunk@101 514c082c-b64e-11dc-b46d-3d985efe055d --- data/apt/cfnetwork.diff | 355 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 data/apt/cfnetwork.diff diff --git a/data/apt/cfnetwork.diff b/data/apt/cfnetwork.diff new file mode 100644 index 000000000..52a2292ff --- /dev/null +++ b/data/apt/cfnetwork.diff @@ -0,0 +1,355 @@ +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-02-25 10:23:18.000000000 +0000 +@@ -44,6 +48,9 @@ + // Internet stuff + #include + ++#include ++#include ++ + #include "connect.h" + #include "rfc2553emu.h" + #include "http.h" +@@ -1062,159 +1069,192 @@ + + if (Queue == 0) + continue; +- +- // Connect to the server +- if (Server == 0 || Server->Comp(Queue->Uri) == false) +- { +- delete Server; +- Server = new ServerState(Queue->Uri,this); ++ ++ CFStringEncoding se = kCFStringEncodingUTF8; ++ ++ CFStringRef sr = CFStringCreateWithCString(kCFAllocatorDefault, Queue->Uri.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(SBuf.st_mtime).c_str(), se); ++ CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("If-Modified-Since"), sr); ++ CFRelease(sr); + } +- +- /* 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; ++ ++ CFHTTPMessageSetHeaderFieldValue(hm, CFSTR("User-Agent"), CFSTR("Telesphoreo APT-HTTP/1.0.98")); ++ CFReadStreamRef rs = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, hm); ++ CFRelease(hm); ++ ++ CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue); ++ CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); ++ ++ URI uri = Queue->Uri; ++ ++ Status("Connecting to %s", uri.Host.c_str()); ++ ++ if (!CFReadStreamOpen(rs)) { ++ Fail(true); ++ 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; +- } +- }; ++ uint8_t data[10240]; ++ CFIndex rd = CFReadStreamRead(rs, data, sizeof(data)); + +- // Decide what to do. + FetchResult Res; + 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); ++ UInt32 sc = CFHTTPMessageGetResponseStatusCode(hm); + +- /* If the server is sending back sizeless responses then fill in +- the size now */ ++ size_t offset = 0; ++ ++ 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) ++ 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; +- } +- +- // 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; ++ 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; ++ } + } +- ++ ++ done: ++ CFRelease(rs); ++ + FailCounter = 0; + } + +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-02-25 10:18:24.000000000 +0000 +@@ -47,7 +47,7 @@ + + # The http method + PROGRAM=http +-SLIBS = -lapt-pkg $(SOCKETLIBS) ++SLIBS = -lapt-pkg $(SOCKETLIBS) -framework CFNetwork -framework CoreFoundation + LIB_MAKES = apt-pkg/makefile + SOURCE = http.cc rfc2553emu.cc connect.cc + include $(PROGRAM_H) -- cgit v1.2.3