]> git.saurik.com Git - cydia.git/blobdiff - MobileCydia.mm
If you have cydia. access, get Token_.
[cydia.git] / MobileCydia.mm
index e5c517e1fcacd477ae5046b43407db7b3667ef17..776c31cefada61e26963eec3f50dd854beb5fd1d 100644 (file)
@@ -206,6 +206,7 @@ void PrintTimes() {
 #define _end }
 /* }}} */
 
+#include "Version.h"
 #define Cydia_ CYDIA_VERSION
 
 #define lprintf(args...) fprintf(stderr, args)
@@ -266,6 +267,11 @@ static _finline void UpdateExternalStatus(uint64_t newStatus) {
     notify_post("com.saurik.Cydia.status");
 }
 
+static CGFloat CYStatusBarHeight(UIInterfaceOrientation orientation) {
+    CGSize size([[UIApplication sharedApplication] statusBarFrame].size);
+    return UIInterfaceOrientationIsPortrait(orientation) ? size.height : size.width;
+}
+
 /* NSForcedOrderingSearch doesn't work on the iPhone */
 static const NSStringCompareOptions MatchCompareOptions_ = NSLiteralSearch | NSCaseInsensitiveSearch;
 static const NSStringCompareOptions LaxCompareOptions_ = NSNumericSearch | NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch | NSCaseInsensitiveSearch;
@@ -703,7 +709,10 @@ static NSString *Idiom_;
 static _H<NSMutableDictionary> SessionData_;
 static _H<NSObject> HostConfig_;
 static _H<NSMutableSet> BridgedHosts_;
+static _H<NSMutableSet> TokenHosts_;
+static _H<NSMutableSet> InsecureHosts_;
 static _H<NSMutableSet> PipelinedHosts_;
+static _H<NSMutableSet> CachedURLs_;
 
 static NSString *kCydiaProgressEventTypeError = @"Error";
 static NSString *kCydiaProgressEventTypeInformation = @"Information";
@@ -3830,10 +3839,14 @@ static _H<NSMutableSet> Diversions_;
     if (false);
     else if (selector == @selector(addBridgedHost:))
         return @"addBridgedHost";
+    else if (selector == @selector(addInsecureHost:))
+        return @"addInsecureHost";
     else if (selector == @selector(addInternalRedirect::))
         return @"addInternalRedirect";
     else if (selector == @selector(addPipelinedHost:scheme:))
         return @"addPipelinedHost";
+    else if (selector == @selector(addTokenHost:))
+        return @"addTokenHost";
     else if (selector == @selector(addTrivialSource:))
         return @"addTrivialSource";
     else if (selector == @selector(close))
@@ -3988,6 +4001,16 @@ static _H<NSMutableSet> Diversions_;
     [BridgedHosts_ addObject:host];
 } }
 
+- (void) addInsecureHost:(NSString *)host {
+@synchronized (HostConfig_) {
+    [InsecureHosts_ addObject:host];
+} }
+
+- (void) addTokenHost:(NSString *)host {
+@synchronized (HostConfig_) {
+    [TokenHosts_ addObject:host];
+} }
+
 - (void) addPipelinedHost:(NSString *)host scheme:(NSString *)scheme {
 @synchronized (HostConfig_) {
     if (scheme != (id) [WebUndefined undefined])
@@ -4206,6 +4229,24 @@ static _H<NSMutableSet> Diversions_;
 @end
 /* }}} */
 
+@interface NSURL (CydiaSecure)
+@end
+
+@implementation NSURL (CydiaSecure)
+
+- (bool) isCydiaSecure {
+    if ([[[self scheme] lowercaseString] isEqualToString:@"https"])
+        return true;
+
+    @synchronized (HostConfig_) {
+        if ([InsecureHosts_ containsObject:[self host]])
+            return true;
+    }
+
+    return false;
+}
+
+@end
 
 /* Cydia Browser Controller {{{ */
 @implementation CydiaWebViewController
@@ -4256,14 +4297,25 @@ static _H<NSMutableSet> Diversions_;
 }
 
 - (NSURLRequest *) webView:(WebView *)view resource:(id)resource willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source {
+    NSURL *url([request URL]);
+    NSString *host([url host]);
+
     NSMutableURLRequest *copy([[super webView:view resource:resource willSendRequest:request redirectResponse:response fromDataSource:source] mutableCopy]);
 
-    if (System_ != NULL)
+    if (System_ != NULL && [copy valueForHTTPHeaderField:@"X-System"] == nil)
         [copy setValue:System_ forHTTPHeaderField:@"X-System"];
-    if (Machine_ != NULL)
+    if (Machine_ != NULL && [copy valueForHTTPHeaderField:@"X-Machine"] == nil)
         [copy setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
-    if (Token_ != nil)
-        [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+
+    bool token;
+    @synchronized (HostConfig_) {
+        token = [TokenHosts_ containsObject:host] || [BridgedHosts_ containsObject:host];
+    }
+
+    if ([url isCydiaSecure] && token) {
+        if (Token_ != nil && [copy valueForHTTPHeaderField:@"X-Cydia-Token"] == nil)
+            [copy setValue:Token_ forHTTPHeaderField:@"X-Cydia-Token"];
+    }
 
     return copy;
 }
@@ -4273,22 +4325,22 @@ static _H<NSMutableSet> Diversions_;
     [cydia_ setDelegate:delegate];
 }
 
-- (id) init {
-    if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) {
-        cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease];
-
-        WebView *webview([[webview_ _documentView] webView]);
+- (NSString *) applicationNameForUserAgent {
+    NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]);
 
-        NSString *application([NSString stringWithFormat:@"Cydia/%@", @ Cydia_]);
+    if (Safari_ != nil)
+        application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application];
+    if (Build_ != nil)
+        application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application];
+    if (Product_ != nil)
+        application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application];
 
-        if (Safari_ != nil)
-            application = [NSString stringWithFormat:@"Safari/%@ %@", Safari_, application];
-        if (Build_ != nil)
-            application = [NSString stringWithFormat:@"Mobile/%@ %@", Build_, application];
-        if (Product_ != nil)
-            application = [NSString stringWithFormat:@"Version/%@ %@", Product_, application];
+    return application;
+}
 
-        [webview setApplicationNameForUserAgent:application];
+- (id) init {
+    if ((self = [super initWithWidth:0 ofClass:[CydiaWebViewController class]]) != nil) {
+        cydia_ = [[[CydiaObject alloc] initWithDelegate:indirect_] autorelease];
     } return self;
 }
 
@@ -5086,12 +5138,19 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     Source *source = [package source];
 
     icon_ = [package icon];
-    name_ = [package name];
 
-    if (IsWildcat_)
-        description_ = [package longDescription];
-    if (description_ == nil)
-        description_ = [package shortDescription];
+    if (NSString *name = [package name])
+        name_ = [NSString stringWithString:name];
+
+    NSString *description(nil);
+
+    if (description == nil && IsWildcat_)
+        description = [package longDescription];
+    if (description == nil)
+        description = [package shortDescription];
+
+    if (description != nil)
+        description_ = [NSString stringWithString:description];
 
     commercial_ = [package isCommercial];
 
@@ -5432,6 +5491,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -5712,15 +5773,27 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self resizeForKeyboardBounds:bounds duration:0];
 }
 
+- (void) getKeyboardCurve:(UIViewAnimationCurve *)curve duration:(NSTimeInterval *)duration forNotification:(NSNotification *)notification {
+    if (&UIKeyboardAnimationCurveUserInfoKey == NULL)
+        *curve = UIViewAnimationCurveEaseInOut;
+    else
+        [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:curve];
+
+    if (&UIKeyboardAnimationDurationUserInfoKey == NULL)
+        *duration = 0.3;
+    else
+        [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:duration];
+}
+
 - (void) keyboardWillShow:(NSNotification *)notification {
     CGRect bounds;
     CGPoint center;
-    NSTimeInterval duration;
-    UIViewAnimationCurve curve;
     [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&bounds];
     [[[notification userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] getValue:&center];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+
+    NSTimeInterval duration;
+    UIViewAnimationCurve curve;
+    [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
 
     CGRect kbframe = CGRectMake(round(center.x - bounds.size.width / 2.0), round(center.y - bounds.size.height / 2.0), bounds.size.width, bounds.size.height);
     UIViewController *base = self;
@@ -5729,14 +5802,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     CGRect viewframe = [[base view] convertRect:[list_ frame] fromView:[list_ superview]];
     CGRect intersection = CGRectIntersection(viewframe, kbframe);
 
+    if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
+        intersection.size.height += CYStatusBarHeight([self interfaceOrientation]);
+
     [self resizeForKeyboardBounds:intersection duration:duration curve:curve];
 }
 
 - (void) keyboardWillHide:(NSNotification *)notification {
     NSTimeInterval duration;
     UIViewAnimationCurve curve;
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];
-    [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];
+    [self getKeyboardCurve:&curve duration:&duration forNotification:notification];
 
     [self resizeForKeyboardBounds:CGRectZero duration:duration curve:curve];
 }
@@ -5854,19 +5929,29 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         packages_ = [NSArray array];
         sections_ = [NSMutableArray arrayWithCapacity:16];
+    } return self;
+}
 
-        list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
-        [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
-        [[self view] addSubview:list_];
+- (void) loadView {
+    [self setView:[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]];
 
-        // XXX: is 20 the most optimal number here?
-        [list_ setSectionIndexMinimumDisplayRowCount:20];
+    list_ = [[[UITableView alloc] initWithFrame:[[self view] bounds] style:UITableViewStylePlain] autorelease];
+    [list_ setAutoresizingMask:UIViewAutoresizingFlexibleBoth];
+    [[self view] addSubview:list_];
 
-        [(UITableView *) list_ setDataSource:self];
-        [list_ setDelegate:self];
+    // XXX: is 20 the most optimal number here?
+    [list_ setSectionIndexMinimumDisplayRowCount:20];
 
-        [self updateHeight];
-    } return self;
+    [(UITableView *) list_ setDataSource:self];
+    [list_ setDelegate:self];
+
+    [self updateHeight];
+}
+
+- (void) releaseSubviews {
+    list_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (void) setDelegate:(id)delegate {
@@ -5895,6 +5980,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         return;
     }
 
+    NSArray *packages;
+
     if ([self shouldYield]) {
         do {
             UIProgressHUD *hud;
@@ -5907,7 +5994,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
             }
 
             reloading_ = 1;
-            packages_ = [self yieldToSelector:@selector(_reloadPackages)];
+            packages = [self yieldToSelector:@selector(_reloadPackages)];
 
             if (hud != nil)
                 [delegate_ removeProgressHUD:hud];
@@ -5915,9 +6002,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
         reloading_ = 0;
     } else {
-        packages_ = [self _reloadPackages];
+        packages = [self _reloadPackages];
     }
 
+    packages_ = packages;
+
     [indices_ removeAllObjects];
     [sections_ removeAllObjects];
 
@@ -6398,16 +6487,18 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (void) unloadData {
-    UIViewController *selected([self selectedViewController]);
+    [super unloadData];
+
     for (UINavigationController *controller in [self viewControllers])
         [controller unloadData];
 
-    [selected reloadData];
+    if (UIViewController *selected = [self selectedViewController])
+        [selected reloadData];
 
-    if (UIViewController *unselected = [self unselectedViewController])
+    if (UIViewController *unselected = [self unselectedViewController]) {
+        [unselected unloadData];
         [unselected reloadData];
-
-    [super unloadData];
+    }
 }
 
 - (void) dealloc {
@@ -6515,14 +6606,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     updatedelegate_ = delegate;
 }
 
-- (CGFloat) statusBarHeight {
-    if (UIInterfaceOrientationIsPortrait([self interfaceOrientation])) {
-        return [[UIApplication sharedApplication] statusBarFrame].size.height;
-    } else {
-        return [[UIApplication sharedApplication] statusBarFrame].size.width;
-    }
-}
-
 - (UIView *) transitionView {
     if ([self respondsToSelector:@selector(_transitionView)])
         return [self _transitionView];
@@ -6541,7 +6624,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     CGRect barframe([refreshbar_ frame]);
 
     if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iPhoneOS_3_0) // XXX: _UIApplicationLinkedOnOrAfter(4)
-        barframe.origin.y = [self statusBarHeight];
+        barframe.origin.y = CYStatusBarHeight([self interfaceOrientation]);
     else
         barframe.origin.y = 0;
 
@@ -6914,6 +6997,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -7091,6 +7176,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -7125,21 +7212,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 } }
 
 - (void) _reloadData {
+    NSArray *packages;
+
   reload:
     if (true) {
         UIProgressHUD *hud([delegate_ addProgressHUD]);
         [hud setText:UCLocalize("LOADING")];
         //NSLog(@"HUD:%@::%@", delegate_, hud);
-        packages_ = [self yieldToSelector:@selector(_reloadPackages)];
+        packages = [self yieldToSelector:@selector(_reloadPackages)];
         [delegate_ removeProgressHUD:hud];
     } else {
-        packages_ = [self _reloadPackages];
+        packages = [self _reloadPackages];
     }
 
 @synchronized (database_) {
     if (era_ != [database_ era])
         goto reload;
 
+    packages_ = packages;
     [sections_ removeAllObjects];
 
     Section *upgradable = [[[Section alloc] initWithName:UCLocalize("AVAILABLE_UPGRADES") localize:NO] autorelease];
@@ -7517,6 +7607,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     table_ = nil;
     ignoredSwitch_ = nil;
     subscribedSwitch_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database package:(NSString *)package {
@@ -7985,8 +8077,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 }
 
 - (NSURLConnection *) _requestHRef:(NSString *)href method:(NSString *)method {
+    NSURL *url([NSURL URLWithString:href]);
+
     NSMutableURLRequest *request = [NSMutableURLRequest
-        requestWithURL:[NSURL URLWithString:href]
+        requestWithURL:url
         cachePolicy:NSURLRequestUseProtocolCachePolicy
         timeoutInterval:120.0
     ];
@@ -7995,8 +8089,11 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
     if (Machine_ != NULL)
         [request setValue:[NSString stringWithUTF8String:Machine_] forHTTPHeaderField:@"X-Machine"];
-    if (UniqueID_ != nil)
-        [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
+
+    if ([url isCydiaSecure]) {
+        if (UniqueID_ != nil)
+            [request setValue:UniqueID_ forHTTPHeaderField:@"X-Unique-ID"];
+    }
 
     return [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
 }
@@ -8078,6 +8175,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) releaseSubviews {
     list_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database {
@@ -8241,6 +8340,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     table_ = nil;
     segment_ = nil;
     container_ = nil;
+
+    [super releaseSubviews];
 }
 
 - (id) initWithDatabase:(Database *)database delegate:(id)delegate {
@@ -8424,6 +8525,14 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [[self view] addSubview:status_];
 }
 
+- (void) releaseSubviews {
+    spinner_ = nil;
+    status_ = nil;
+    caption_ = nil;
+
+    [super releaseSubviews];
+}
+
 @end
 /* }}} */
 
@@ -8454,6 +8563,24 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 #endif
 }
 
+- (void) storeCachedResponse:(NSCachedURLResponse *)cached forRequest:(NSURLRequest *)request {
+    if (NSURLResponse *response = [cached response])
+        if (NSString *mime = [response MIMEType])
+            if ([mime isEqualToString:@"text/cache-manifest"]) {
+                NSURL *url([response URL]);
+
+#if !ForRelease
+                NSLog(@"###: %@", [url absoluteString]);
+#endif
+
+                @synchronized (HostConfig_) {
+                    [CachedURLs_ addObject:url];
+                }
+            }
+
+    [super storeCachedResponse:cached forRequest:request];
+}
+
 @end
 
 @interface Cydia : UIApplication <
@@ -8632,7 +8759,8 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [NSThread detachNewThreadSelector:@selector(_refreshIfPossible:) toTarget:self withObject:[Metadata_ objectForKey:@"LastUpdate"]];
 }
 
-- (void) _reloadDataWithInvocation:(NSInvocation *)invocation {
+- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
+@synchronized (self) {
     UIProgressHUD *hud(loaded_ ? [self addProgressHUD] : nil);
     [hud setText:UCLocalize("RELOADING_DATA")];
 
@@ -8657,8 +8785,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
         }
     }
 
-    NSLog(@"changes:#%u", changes);
-
     UITabBarItem *changesItem = [[[tabbar_ viewControllers] objectAtIndex:2] tabBarItem];
     if (changes != 0) {
         _trace();
@@ -8676,7 +8802,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self _updateData];
 
     [self refreshIfPossible];
-}
+} }
 
 - (void) updateData {
     [self _updateData];
@@ -8684,12 +8810,7 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
 
 - (void) update_ {
     [database_ update];
-}
-
-- (void) complete {
-    @synchronized (self) {
-        [self _reloadDataWithInvocation:nil];
-    }
+    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
 }
 
 - (void) disemulate {
@@ -8746,6 +8867,10 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     [self performSelectorOnMainThread:@selector(repairWithInvocation:) withObject:[NSInvocation invocationWithSelector:selector forTarget:database_] waitUntilDone:YES];
 }
 
+- (void) reloadData {
+    [self reloadDataWithInvocation:nil];
+}
+
 - (void) syncData {
     [self _saveConfig];
 
@@ -8765,8 +8890,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     fclose(file);
 
     [self detachNewProgressSelector:@selector(update_) toTarget:self forController:nil title:@"UPDATING_SOURCES"];
-
-    [self complete];
 }
 
 - (void) addTrivialSource:(NSString *)href {
@@ -8779,16 +8902,6 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     Changed_ = true;
 }
 
-- (void) reloadDataWithInvocation:(NSInvocation *)invocation {
-    @synchronized (self) {
-        [self _reloadDataWithInvocation:invocation];
-    }
-}
-
-- (void) reloadData {
-    [self reloadDataWithInvocation:nil];
-}
-
 - (void) resolve {
     pkgProblemResolver *resolver = [database_ resolver];
 
@@ -8866,12 +8979,16 @@ bool DepSubstrate(const pkgCache::VerIterator &iterator) {
     }
 }
 
+- (void) perform_ {
+    [database_ perform];
+    [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
+}
+
 - (void) confirmWithNavigationController:(UINavigationController *)navigation {
     Queuing_ = false;
     ++locked_;
-    [self detachNewProgressSelector:@selector(perform) toTarget:database_ forController:navigation title:@"RUNNING"];
+    [self detachNewProgressSelector:@selector(perform_) toTarget:self forController:navigation title:@"RUNNING"];
     --locked_;
-    [self complete];
 }
 
 - (void) showSettings {
@@ -9537,6 +9654,8 @@ MSHook(id, NSURLConnection$init$, NSURLConnection *self, SEL _cmd, NSURLRequest
     NSMutableURLRequest *copy([request mutableCopy]);
 
     NSURL *url([copy URL]);
+
+    NSString *href([url absoluteString]);
     NSString *host([url host]);
     NSString *scheme([[url scheme] lowercaseString]);
 
@@ -9546,6 +9665,20 @@ MSHook(id, NSURLConnection$init$, NSURLConnection *self, SEL _cmd, NSURLRequest
         if ([copy respondsToSelector:@selector(setHTTPShouldUsePipelining:)])
             if ([PipelinedHosts_ containsObject:host] || [PipelinedHosts_ containsObject:compound])
                 [copy setHTTPShouldUsePipelining:YES];
+
+        if (NSString *control = [copy valueForHTTPHeaderField:@"Cache-Control"])
+            if ([control isEqualToString:@"max-age=0"])
+                if ([CachedURLs_ containsObject:href]) {
+#if !ForRelease
+                    NSLog(@"~~~: %@", href);
+#endif
+
+                    [copy setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
+
+                    [copy setValue:nil forHTTPHeaderField:@"Cache-Control"];
+                    [copy setValue:nil forHTTPHeaderField:@"If-Modified-Since"];
+                    [copy setValue:nil forHTTPHeaderField:@"If-None-Match"];
+                }
     }
 
     if ((self = _NSURLConnection$init$(self, _cmd, copy, delegate, usesCache, maxContentLength, startImmediately, connectionProperties)) != nil) {
@@ -9589,7 +9722,10 @@ int main(int argc, char *argv[]) {
     HostConfig_ = [[[NSObject alloc] init] autorelease];
     @synchronized (HostConfig_) {
         BridgedHosts_ = [NSMutableSet setWithCapacity:4];
+        TokenHosts_ = [NSMutableSet setWithCapacity:4];
+        InsecureHosts_ = [NSMutableSet setWithCapacity:4];
         PipelinedHosts_ = [NSMutableSet setWithCapacity:4];
+        CachedURLs_ = [NSMutableSet setWithCapacity:32];
     }
 
     UI_ = CydiaURL([NSString stringWithFormat:@"ui/ios~%@", Idiom_]);