+/* Cydget - open-source AwayView plugin multiplexer
+ * Copyright (C) 2009-2014 Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia. If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#include <CydiaSubstrate/CydiaSubstrate.h>
+#include <UIKit/UIKit.h>
+
+#include <sys/sysctl.h>
+#include <pthread.h>
+
+#include <WebKit/WebFrame.h>
+#include <WebKit/WebView.h>
+
+#include <map>
+
+#include "yieldToSelector.h"
+
+_disused static unsigned trace_;
+
+#define _trace() do { \
+ NSLog(@"_trace(%u)@%s:%u[%s](%p)\n", \
+ trace_++, __FILE__, __LINE__, __FUNCTION__, pthread_self() \
+ ); \
+} while (false)
+
+#define _assert(test) do \
+ if (!(test)) { \
+ NSLog(@"_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
+ exit(-1); \
+ } \
+while (false)
+
+#define _syscall(expr) \
+ do if ((long) (expr) != -1) \
+ break; \
+ else switch (errno) { \
+ case EINTR: \
+ continue; \
+ default: \
+ _assert(false); \
+ } while (true)
+
+extern "C" UIImage *_UIImageWithName(NSString *name);
+
+typedef uint16_t UChar;
+
+@interface UIApplication (Apple)
+- (void) applicationOpenURL:(NSURL *)url;
+@end
+
+@interface UIScroller : UIView
+- (CGSize) contentSize;
+- (void) setOffset:(CGPoint)offset;
+@end
+
+@interface UIWebDocumentView : UIView
+- (WebView *) webView;
+@end
+
+@interface UIView (Apple)
+- (UIScroller *) _scroller;
+@end
+
+static bool iOS32, iOS4;
+
+@interface NSString (UIKit)
+- (NSString *) stringByAddingPercentEscapes;
+@end
+
+@implementation UIWebDocumentView (WebCycript)
+
+- (void) _setScrollerOffset:(CGPoint)offset {
+ UIScroller *scroller([self _scroller]);
+
+ CGSize size([scroller contentSize]);
+ CGSize bounds([scroller bounds].size);
+
+ CGPoint max;
+ max.x = size.width - bounds.width;
+ max.y = size.height - bounds.height;
+
+ // wtf Apple?!
+ if (max.x < 0)
+ max.x = 0;
+ if (max.y < 0)
+ max.y = 0;
+
+ offset.x = offset.x < 0 ? 0 : offset.x > max.x ? max.x : offset.x;
+ offset.y = offset.y < 0 ? 0 : offset.y > max.y ? max.y : offset.y;
+
+ [scroller setOffset:offset];
+}
+
+@end
+
+@interface DOMCSSStyleSheet : NSObject
+- (int) addRule:(NSString *)rule style:(NSString *)style index:(unsigned)index;
+- (void) deleteRule:(unsigned)index;
+@end
+
+@interface DOMStyleSheetList : NSObject
+- (DOMCSSStyleSheet *) item:(unsigned)index;
+@end
+
+@interface DOMDocument : NSObject
+- (DOMStyleSheetList *) styleSheets;
+@end
+
+@interface NSURL (Apple)
+- (BOOL) isSpringboardHandledURL;
+@end
+
+@interface UIWebView (Apple)
+- (UIWebDocumentView *) _documentView;
+- (void) setDataDetectorTypes:(NSInteger)types;
+- (void) _setDrawInWebThread:(BOOL)draw;
+- (UIScrollView *) _scrollView;
+- (UIScroller *) _scroller;
+- (void) webView:(WebView *)view addMessageToConsole:(NSDictionary *)message;
+- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame;
+@end
+
+@protocol CydgetWebViewDelegate <UIWebViewDelegate>
+- (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame;
+@end
+
+MSClassHook(UIApplication)
+
+MSInstanceMessageHook1(void, UIApplication, openURL, NSURL *, url) {
+ [self applicationOpenURL:url];
+}
+
+@implementation NSURL (Cydget)
+
+- (NSNumber *) cydget$isSpringboardHandledURL {
+ return [NSNumber numberWithBool:[self isSpringboardHandledURL]];
+}
+
+@end
+
+MSClassHook(NSURL)
+
+MSInstanceMessageHook0(BOOL, NSURL, isSpringboardHandledURL) {
+ if (![NSThread isMainThread])
+ return MSOldCall();
+
+ return [[self cydget$yieldToSelector:@selector(cydget$isSpringboardHandledURL)] boolValue];
+}
+
+@implementation UIWebView (WebCycript)
+
+- (void) updateStyles {
+ DOMCSSStyleSheet *sheet([[[[[[self _documentView] webView] mainFrame] DOMDocument] styleSheets] item:0]);
+ [sheet addRule:@"cydget" style:@"color: black" index:0];
+ [sheet deleteRule:0];
+}
+
+@end
+
+extern "C" void WebCycriptSetupView(WebView *webview) {
+ if (void *handle = dlopen("/usr/lib/libcycript.dylib", RTLD_LAZY | RTLD_GLOBAL))
+ if (void (*CYSetupContext)(JSGlobalContextRef) = reinterpret_cast<void (*)(JSGlobalContextRef)>(dlsym(handle, "CydgetSetupContext"))) {
+ WebFrame *frame([webview mainFrame]);
+ JSGlobalContextRef context([frame globalContext]);
+ @try {
+ CYSetupContext(context);
+ } @catch (NSException *e) {
+ NSLog(@"*** CydgetSetupContext => %@", e);
+ }
+ }
+}
+
+#include <string>
+
+struct State {
+ unsigned state;
+};
+
+namespace JSC {
+ class JSGlobalData;
+ class UString;
+}
+
+namespace WebCore {
+ class KURL;
+}
+
+namespace WebCore {
+struct String {
+ void *impl_;
+}; }
+
+namespace JSC {
+struct SourceCode {
+ void *provider_;
+ int start_;
+ int end_;
+ int line_;
+}; }
+
+namespace JSC {
+union ScriptSourceCode {
+ struct {
+ JSC::SourceCode source_;
+ } Old;
+ struct {
+ void *provider_;
+ JSC::SourceCode source_;
+ } New;
+}; }
+
+class CFStringStruct {
+ private:
+ CFStringRef value_;
+
+ public:
+ CFStringStruct() :
+ value_(NULL)
+ {
+ }
+
+ CFStringStruct(const CFStringStruct &value) :
+ value_((CFStringRef) CFRetain(value.value_))
+ {
+ }
+
+ ~CFStringStruct() {
+ [*this autorelease];
+ }
+
+ operator CFStringRef() const {
+ return value_;
+ }
+
+ operator NSString *() const {
+ return (NSString *) value_;
+ }
+};
+
+// String Helpers {{{
+static const UChar *(*_ZNK7WebCore6String10charactersEv)(const WebCore::String *);
+static const UChar *(*_ZN7WebCore6String29charactersWithNullTerminationEv)(const WebCore::String *);
+static CFStringStruct (*_ZNK3WTF6String14createCFStringEv)(const WebCore::String *);
+static unsigned (*_ZNK7WebCore6String6lengthEv)(const WebCore::String *);
+
+static bool StringGet(const WebCore::String &string, const UChar *&data, size_t &length) {
+ bool terminated;
+
+ if (false) {
+ } else if (_ZNK7WebCore6String10charactersEv != NULL) {
+ data = (*_ZNK7WebCore6String10charactersEv)(&string);
+ terminated = false;
+ } else if (_ZN7WebCore6String29charactersWithNullTerminationEv != NULL) {
+ data = (*_ZN7WebCore6String29charactersWithNullTerminationEv)(&string);
+ terminated = true;
+ } else if (_ZNK3WTF6String14createCFStringEv != NULL) {
+ CFStringStruct cf((*_ZNK3WTF6String14createCFStringEv)(&string));
+ data = (const UChar *) [cf cStringUsingEncoding:NSUTF16StringEncoding];
+ length = CFStringGetLength(cf);
+ return true;
+ } else return false;
+
+ if (data == NULL)
+ return false;
+
+ if (_ZNK7WebCore6String6lengthEv != NULL)
+ length = (*_ZNK7WebCore6String6lengthEv)(&string);
+ else if (terminated)
+ for (length = 0; data[length] != 0; ++length);
+ else return false;
+
+ return true;
+}
+
+static bool StringEquals(const WebCore::String &string, const char *value) {
+ const UChar *data;
+ size_t size;
+ if (!StringGet(string, data, size))
+ return false;
+
+ size_t length(strlen(value));
+ if (size != length)
+ return false;
+
+ for (size_t index(0); index != length; ++index)
+ if (data[index] != value[index])
+ return false;
+
+ return true;
+}
+// }}}
+// State Machine {{{
+static bool cycript_;
+
+MSHook(bool, _ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE, const WebCore::String &mime) {
+ if (!StringEquals(mime, "text/cycript")) {
+ cycript_ = false;
+ return __ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE(mime);
+ }
+
+ static void *handle(dlopen("/usr/lib/libcycript.dylib", RTLD_LAZY | RTLD_GLOBAL));
+ if (handle == NULL)
+ return false;
+
+ cycript_ = true;
+ return true;
+}
+// }}}
+// Script Compiler {{{
+static void Log(const WebCore::String &string) {
+#if 0
+ const UChar *data;
+ size_t length;
+ if (!StringGet(string, data, length))
+ return;
+
+ UChar terminated[length + 1];
+ terminated[length] = 0;
+ memcpy(terminated, data, length * 2);
+ NSLog(@"wtf %p:%zu:%S:", &string, length, terminated);
+#endif
+}
+
+static bool Cycriptify(const uint16_t *&data, size_t &size) {
+ cycript_ = false;
+
+ if (void *handle = dlopen("/usr/lib/libcycript.dylib", RTLD_LAZY | RTLD_GLOBAL))
+ if (void (*CydgetMemoryParse)(const uint16_t **, size_t *) = reinterpret_cast<void (*)(const uint16_t **, size_t *)>(dlsym(handle, "CydgetMemoryParse"))) @try {
+ CydgetMemoryParse(&data, &size);
+ return true;
+ } @catch (NSException *e) {
+ NSLog(@"*** CydgetMemoryParse => %@", e);
+ }
+ return false;
+}
+
+static void (*_ZN7WebCore6String6appendEPKtj)(WebCore::String *, const UChar *, unsigned);
+static void (*_ZN7WebCore6String8truncateEj)(WebCore::String *, unsigned);
+
+static void Cycriptify(const WebCore::String &source, int *psize = NULL) {
+ if (!cycript_)
+ return;
+ cycript_ = false;
+
+ const UChar *data;
+ size_t length;
+ if (!StringGet(source, data, length))
+ return;
+
+ size_t size(length);
+ if (!Cycriptify(data, size))
+ return;
+
+ WebCore::String &script(const_cast<WebCore::String &>(source));
+ _ZN7WebCore6String8truncateEj(&script, 0);
+ _ZN7WebCore6String6appendEPKtj(&script, data, size);
+
+ if (psize != NULL)
+ *psize = size;
+
+ free((void *) data);
+
+ Log(source);
+}
+// }}}
+
+static WebCore::String *string;
+
+// iOS 2.x
+MSHook(State, _ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i, void *_this, const WebCore::String &string, State state, const WebCore::String &url, int line) {
+ Cycriptify(string);
+ return __ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i(_this, string, state, url, line);
+}
+
+// iOS 3.x
+MSHook(void, _ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE, JSC::SourceCode **_this, JSC::JSGlobalData *global, int *line, JSC::UString *message) {
+ /*if (cycript_) {
+ JSC::SourceCode *source(_this[iOS32 ? 6 : 0]);
+ const uint16_t *data(source->data());
+ size_t size(source->length());
+
+ if (Cycriptify(data, size)) {
+ source->~SourceCode();
+ // XXX: I actually don't have the original URL here: pants
+ new (source) JSC::SourceCode(JSC::UStringSourceProvider::create(JSC::UString(data, size), "cycript://"), 1);
+ free((void *) data);
+ }
+ }*/
+
+ return __ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE(_this, global, line, message);
+}
+
+// iOS 3.x cdata
+MSHook(const WebCore::String &, _ZNK7WebCore4Node11textContentEb, void *_this, bool convert) {
+ const WebCore::String &code(__ZNK7WebCore4Node11textContentEb(_this, convert));
+ string = const_cast<WebCore::String *>(&code);
+ Cycriptify(code);
+ return code;
+}
+
+// iOS 4.x cdata
+MSHook(void, _ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi, void *_this, const WebCore::String &source, const WebCore::KURL &url, int line) {
+ Cycriptify(source);
+ return __ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi(_this, source, url, line);
+}
+
+// iOS 4.x+5.0 @src=
+MSHook(const WebCore::String &, _ZN7WebCore12CachedScript6scriptEv, void *_this) {
+ const WebCore::String &script(__ZN7WebCore12CachedScript6scriptEv(_this));
+ string = const_cast<WebCore::String *>(&script);
+ return script;
+}
+
+// iOS 4.x @src=
+MSHook(State, _ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE, void *_this, JSC::ScriptSourceCode &script, State state) {
+ if (string != NULL) {
+ JSC::SourceCode *source(iOS4 ? &script.New.source_ : &script.Old.source_);
+ Cycriptify(*string, &source->end_);
+ string = NULL;
+ }
+
+ return __ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE(_this, script, state);
+}
+
+// iOS 5.0 cdata
+MSHook(void, _ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE, void *_this, const WebCore::String &source, const WebCore::KURL &url, void *position) {
+ Cycriptify(source);
+ return __ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE(_this, source, url, position);
+}
+
+// iOS 5.0 @src=
+MSHook(void, _ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE, void *_this, void *position, int legacy) {
+ string = NULL;
+ return __ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE(_this, position, legacy);
+}
+
+void (*$_ZNK7WebCore13ScriptElement21isScriptTypeSupportedENS0_17LegacyTypeSupportE)(void *_this, int legacy);
+
+// iOS 5.0 @src=
+MSHook(void, _ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE, void *_this, JSC::ScriptSourceCode &script) {
+ if (string != NULL) {
+ JSC::SourceCode *source(&script.New.source_);
+ $_ZNK7WebCore13ScriptElement21isScriptTypeSupportedENS0_17LegacyTypeSupportE(_this, 0);
+ Cycriptify(*string, &source->end_);
+ string = NULL;
+ }
+
+ return __ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE(_this, script);
+}
+
+// iOS 6.0 cdata
+MSHook(void, _ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE, void *_this, const WebCore::String &source, const WebCore::KURL &url, void *position) {
+ Cycriptify(source);
+ return __ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE(_this, source, url, position);
+}
+
+// iOS 6.0 @src=
+MSHook(void, _ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE, void *_this, void *position, int legacy) {
+ string = NULL;
+ return __ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE(_this, position, legacy);
+}
+
+/* Cydget:// Protocol {{{ */
+@interface CydgetURLProtocol : NSURLProtocol {
+}
+
+@end
+
+@implementation CydgetURLProtocol
+
++ (BOOL) canInitWithRequest:(NSURLRequest *)request {
+ NSURL *url([request URL]);
+ if (url == nil)
+ return NO;
+ NSString *scheme([[url scheme] lowercaseString]);
+ if (scheme == nil || ![scheme isEqualToString:@"cydget"])
+ return NO;
+ return YES;
+}
+
++ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
+ return request;
+}
+
+- (void) _returnPNGWithImage:(UIImage *)icon forRequest:(NSURLRequest *)request {
+ id<NSURLProtocolClient> client([self client]);
+ if (icon == nil)
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
+ else {
+ NSData *data(UIImagePNGRepresentation(icon));
+
+ NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:@"image/png" expectedContentLength:-1 textEncodingName:nil] autorelease]);
+ [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ [client URLProtocol:self didLoadData:data];
+ [client URLProtocolDidFinishLoading:self];
+ }
+}
+
+- (void) startLoading {
+ id<NSURLProtocolClient> client([self client]);
+ NSURLRequest *request([self request]);
+
+ NSURL *url([request URL]);
+ NSString *href([url absoluteString]);
+
+ NSString *path([href substringFromIndex:9]);
+ NSRange slash([path rangeOfString:@"/"]);
+
+ NSString *command;
+ if (slash.location == NSNotFound) {
+ command = path;
+ path = nil;
+ } else {
+ command = [path substringToIndex:slash.location];
+ path = [path substringFromIndex:(slash.location + 1)];
+ }
+
+ if ([command isEqualToString:@"_UIImageWithName"]) {
+ if (path == nil)
+ goto fail;
+ path = [path stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ UIImage *icon(_UIImageWithName(path));
+ [self _returnPNGWithImage:icon forRequest:request];
+ } else fail: {
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
+ }
+}
+
+- (void) stopLoading {
+}
+
+@end
+/* }}} */
+/* Cydget-CGI:// Protocol {{{ */
+@interface CydgetCGIURLProtocol : NSURLProtocol {
+ pid_t pid_;
+ CFHTTPMessageRef http_;
+ NSFileHandle *handle_;
+}
+
+@end
+
+@implementation CydgetCGIURLProtocol
+
++ (BOOL) canInitWithRequest:(NSURLRequest *)request {
+ NSURL *url([request URL]);
+ if (url == nil)
+ return NO;
+ NSString *scheme([[url scheme] lowercaseString]);
+ if (scheme == nil || ![scheme isEqualToString:@"cydget-cgi"])
+ return NO;
+ return YES;
+}
+
++ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
+ return request;
+}
+
+- (id) initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)response client:(id<NSURLProtocolClient>)client {
+ if ((self = [super initWithRequest:request cachedResponse:response client:client]) != nil) {
+ pid_ = -1;
+ } return self;
+}
+
+- (void) startLoading {
+ id<NSURLProtocolClient> client([self client]);
+ NSURLRequest *request([self request]);
+ NSURL *url([request URL]);
+
+ NSString *path([url path]);
+ if (path == nil) {
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
+ return;
+ }
+
+ NSFileManager *manager([NSFileManager defaultManager]);
+ if (![manager fileExistsAtPath:path]) {
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]];
+ return;
+ }
+
+ int fds[2];
+ _assert(pipe(fds) != -1);
+
+ _assert(pid_ == -1);
+ pid_ = fork();
+ if (pid_ == -1) {
+ _assert(close(fds[0]) != -1);
+ _assert(close(fds[1]) != -1);
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil]];
+ return;
+ }
+
+ if (pid_ == 0) {
+ const char *script([path UTF8String]);
+
+ setenv("GATEWAY_INTERFACE", "CGI/1.1", true);
+ setenv("SCRIPT_FILENAME", script, true);
+ NSString *query([url query]);
+ if (query != nil)
+ setenv("QUERY_STRING", [query UTF8String], true);
+
+ _assert(dup2(fds[1], 1) != -1);
+ _assert(close(fds[0]) != -1);
+ _assert(close(fds[1]) != -1);
+
+ execl(script, script, NULL);
+ exit(1);
+ _assert(false);
+ }
+
+ _assert(close(fds[1]) != -1);
+
+ _assert(http_ == NULL);
+ http_ = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, FALSE);
+ CFHTTPMessageAppendBytes(http_, (const uint8_t *) "HTTP/1.1 200 OK\r\n", 17);
+
+ _assert(handle_ == nil);
+ handle_ = [[NSFileHandle alloc] initWithFileDescriptor:fds[0] closeOnDealloc:YES];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(onRead:)
+ name:@"NSFileHandleReadCompletionNotification"
+ object:handle_
+ ];
+
+ [handle_ readInBackgroundAndNotify];
+}
+
+- (void) onRead:(NSNotification *)notification {
+ NSFileHandle *handle([notification object]);
+
+ NSData *data([[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]);
+
+ if (size_t length = [data length]) {
+ CFHTTPMessageAppendBytes(http_, reinterpret_cast<const UInt8 *>([data bytes]), length);
+ [handle readInBackgroundAndNotify];
+ } else {
+ id<NSURLProtocolClient> client([self client]);
+
+ CFStringRef mime(CFHTTPMessageCopyHeaderFieldValue(http_, CFSTR("Content-type")));
+ if (mime == NULL)
+ [client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:nil]];
+ else {
+ NSURLRequest *request([self request]);
+
+ NSURLResponse *response([[[NSURLResponse alloc] initWithURL:[request URL] MIMEType:(NSString *)mime expectedContentLength:-1 textEncodingName:nil] autorelease]);
+ CFRelease(mime);
+
+ [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+
+ CFDataRef body(CFHTTPMessageCopyBody(http_));
+ [client URLProtocol:self didLoadData:(NSData *)body];
+ CFRelease(body);
+
+ [client URLProtocolDidFinishLoading:self];
+ }
+
+ CFRelease(http_);
+ http_ = NULL;
+ }
+}
+
+ //[client URLProtocol:self didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNetworkConnectionLost userInfo:nil]];
+
+- (void) stopLoading_ {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if (handle_ != nil) {
+ [handle_ release];
+ handle_ = nil;
+ }
+
+ if (pid_ != -1) {
+ kill(pid_, SIGTERM);
+ int status;
+ _syscall(waitpid(pid_, &status, 0));
+ pid_ = -1;
+ }
+}
+
+- (void) stopLoading {
+ [self
+ performSelectorOnMainThread:@selector(stopLoading_)
+ withObject:nil
+ waitUntilDone:NO
+ ];
+}
+
+@end
+/* }}} */
+
+namespace WebCore {
+ class MediaQueryEvaluator;
+ class CSSParserValueList;
+}
+
+namespace WebCore {
+struct MediaQueryExp {
+ String feature_;
+ void *value_;
+ bool valid_;
+ String cache_;
+}; }
+
+typedef std::map<std::string, BOOL (*)()> StyleMap_;
+static StyleMap_ styles_;
+
+extern "C" void WebCycriptRegisterStyle(const char *name, BOOL (*code)()) {
+ styles_.insert(std::make_pair(name, code));
+}
+
+MSHook(bool, _ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE, WebCore::MediaQueryEvaluator *_this, WebCore::String &query) {
+ Log(query);
+ for (StyleMap_::const_iterator style(styles_.begin()); style != styles_.end(); ++style)
+ if (StringEquals(query, style->first.c_str()))
+ return style->second();
+ return __ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE(_this, query);
+}
+
+MSHook(void *, _ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE, WebCore::MediaQueryExp *_this, WebCore::String &query, WebCore::CSSParserValueList *values) {
+ Log(query);
+ void *value(__ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE(_this, query, values));
+ if (!_this->valid_)
+ for (StyleMap_::const_iterator style(styles_.begin()); style != styles_.end(); ++style)
+ if (StringEquals(query, style->first.c_str()))
+ _this->valid_ = true;
+ return value;
+}
+
+template <typename Type_>
+static void dlset(Type_ &function, const char *name) {
+ function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
+}
+
+#define msset(function, handle) \
+ MSHookSymbol(function, "_" #function, handle)
+
+MSInitialize {
+ iOS4 = kCFCoreFoundationVersionNumber >= 550.32;
+ iOS32 = !iOS4 && kCFCoreFoundationVersionNumber >= 478.61;
+
+ int maxproc;
+ size_t size(sizeof(maxproc));
+ if (sysctlbyname("kern.maxproc", &maxproc, &size, NULL, 0) == -1)
+ NSLog(@"sysctlbyname(\"kern.maxproc\", ?)");
+ else if (maxproc < 72) {
+ maxproc = 72;
+ if (sysctlbyname("kern.maxproc", NULL, NULL, &maxproc, sizeof(maxproc)) == -1)
+ NSLog(@"sysctlbyname(\"kern.maxproc\", #)");
+ }
+
+ [NSURLProtocol registerClass:[CydgetURLProtocol class]];
+ [WebView registerURLSchemeAsLocal:@"cydget"];
+
+ [NSURLProtocol registerClass:[CydgetCGIURLProtocol class]];
+ [WebView registerURLSchemeAsLocal:@"cydget-cgi"];
+
+ MSImageRef JavaScriptCore(NULL);
+ if (JavaScriptCore == NULL)
+ JavaScriptCore = MSGetImageByName("/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore");
+ if (JavaScriptCore == NULL)
+ JavaScriptCore = MSGetImageByName("/System/Library/PrivateFrameworks/JavaScriptCore.framework/JavaScriptCore");
+
+ MSImageRef WebCore(MSGetImageByName("/System/Library/PrivateFrameworks/WebCore.framework/WebCore"));
+
+ if (!iOS4) {
+ void (*_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE)(JSC::SourceCode **, JSC::JSGlobalData *, int *, JSC::UString *);
+ dlset(_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE, "_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE");
+ if (_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE != NULL)
+ MSHookFunction(_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE, MSHake(_ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE));
+ }
+
+ bool (*_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE)(const WebCore::String &) = NULL;
+ if (_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE == NULL)
+ MSHookSymbol(_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE, "__ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE", WebCore);
+ if (_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE == NULL)
+ MSHookSymbol(_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE, "__ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKN3WTF6StringE", WebCore);
+ if (_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE != NULL)
+ MSHookFunction(_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE, MSHake(_ZN7WebCore16MIMETypeRegistry29isSupportedJavaScriptMIMETypeERKNS_6StringE));
+
+ void (*_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi)(void *, const WebCore::String &, const WebCore::KURL &, int) = NULL;
+ if (_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi == NULL)
+ MSHookSymbol(_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi, "__ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi", WebCore);
+ if (_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi != NULL)
+ MSHookFunction(_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi, MSHake(_ZN7WebCore16ScriptSourceCodeC2ERKNS_6StringERKNS_4KURLEi));
+
+ if (!iOS4) {
+ const WebCore::String &(*_ZNK7WebCore4Node11textContentEb)(void *, bool) = NULL;
+ if (_ZNK7WebCore4Node11textContentEb == NULL)
+ MSHookSymbol(_ZNK7WebCore4Node11textContentEb, "__ZNK7WebCore4Node11textContentEb", WebCore);
+ if (_ZNK7WebCore4Node11textContentEb != NULL)
+ MSHookFunction(_ZNK7WebCore4Node11textContentEb, MSHake(_ZNK7WebCore4Node11textContentEb));
+ }
+
+ const WebCore::String &(*_ZN7WebCore12CachedScript6scriptEv)(void *) = NULL;
+ if (_ZN7WebCore12CachedScript6scriptEv == NULL)
+ MSHookSymbol(_ZN7WebCore12CachedScript6scriptEv, "__ZN7WebCore12CachedScript6scriptEv", WebCore);
+ if (_ZN7WebCore12CachedScript6scriptEv != NULL)
+ MSHookFunction(_ZN7WebCore12CachedScript6scriptEv, MSHake(_ZN7WebCore12CachedScript6scriptEv));
+
+ State (*_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i)(void *, const WebCore::String &, State, const WebCore::String &, int) = NULL;
+ if (_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i == NULL)
+ MSHookSymbol(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i, "__ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i", WebCore);
+ if (_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i != NULL)
+ MSHookFunction(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i, MSHake(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_6StringENS0_5StateES3_i));
+
+ State (*_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE)(void *, JSC::ScriptSourceCode &, State) = NULL;
+ if (_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE == NULL)
+ MSHookSymbol(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE, "__ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE", WebCore);
+ if (_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE != NULL)
+ MSHookFunction(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE, MSHake(_ZN7WebCore13HTMLTokenizer15scriptExecutionERKNS_16ScriptSourceCodeENS0_5StateE));
+
+ void (*_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE)(void *, const WebCore::String &, const WebCore::KURL &, void *);
+ msset(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE, WebCore);
+ if (_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE != NULL)
+ MSHookFunction(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE, MSHake(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionINS1_14OneBasedNumberEEE));
+
+ void (*_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE)(void *, const WebCore::String &, const WebCore::KURL &, void *);
+ msset(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE, WebCore);
+ if (_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE == NULL)
+ MSHookSymbol(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE, "__ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_3URLERKNS1_12TextPositionE", WebCore);
+ if (_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE != NULL)
+ MSHookFunction(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE, MSHake(_ZN7WebCore16ScriptSourceCodeC2ERKN3WTF6StringERKNS_4KURLERKNS1_12TextPositionE));
+
+ void (*_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE)(void *, void *, int);
+ msset(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE, WebCore);
+ if (_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE != NULL)
+ MSHookFunction(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE, MSHake(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionINS1_14OneBasedNumberEEENS0_17LegacyTypeSupportE));
+
+ void (*_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE)(void *, void *, int);
+ msset(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE, WebCore);
+ if (_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE != NULL)
+ MSHookFunction(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE, MSHake(_ZN7WebCore13ScriptElement13prepareScriptERKN3WTF12TextPositionENS0_17LegacyTypeSupportE));
+
+ MSHookSymbol($_ZNK7WebCore13ScriptElement21isScriptTypeSupportedENS0_17LegacyTypeSupportE, "__ZNK7WebCore13ScriptElement21isScriptTypeSupportedENS0_17LegacyTypeSupportE", WebCore);
+
+ void (*_ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE)(void *, JSC::ScriptSourceCode &);
+ msset(_ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE, WebCore);
+ if (_ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE != NULL)
+ MSHookFunction(_ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE, MSHake(_ZN7WebCore13ScriptElement13executeScriptERKNS_16ScriptSourceCodeE));
+
+ if (_ZN7WebCore6String6appendEPKtj == NULL)
+ MSHookSymbol(_ZN7WebCore6String6appendEPKtj, "__ZN7WebCore6String6appendEPKtj", WebCore);
+ if (_ZN7WebCore6String6appendEPKtj == NULL)
+ msset(_ZN7WebCore6String6appendEPKtj, JavaScriptCore);
+ if (_ZN7WebCore6String6appendEPKtj == NULL)
+ MSHookSymbol(_ZN7WebCore6String6appendEPKtj, "__ZN3WTF6String6appendEPKtj", JavaScriptCore);
+
+ if (_ZN7WebCore6String8truncateEj == NULL)
+ MSHookSymbol(_ZN7WebCore6String8truncateEj, "__ZN7WebCore6String8truncateEj", WebCore);
+ if (_ZN7WebCore6String8truncateEj == NULL)
+ msset(_ZN7WebCore6String8truncateEj, JavaScriptCore);
+ if (_ZN7WebCore6String8truncateEj == NULL)
+ MSHookSymbol(_ZN7WebCore6String8truncateEj, "__ZN3WTF6String8truncateEj", JavaScriptCore);
+
+ msset(_ZNK7WebCore6String10charactersEv, WebCore);
+
+ msset(_ZN7WebCore6String29charactersWithNullTerminationEv, JavaScriptCore);
+ if (_ZN7WebCore6String29charactersWithNullTerminationEv == NULL)
+ MSHookSymbol(_ZN7WebCore6String29charactersWithNullTerminationEv, "__ZN3WTF6String29charactersWithNullTerminationEv", JavaScriptCore);
+
+ msset(_ZNK3WTF6String14createCFStringEv, JavaScriptCore);
+
+ msset(_ZNK7WebCore6String6lengthEv, WebCore);
+
+ bool (*_ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE)(WebCore::MediaQueryEvaluator *, WebCore::String &);
+ msset(_ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE, WebCore);
+ if (_ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE != NULL)
+ MSHookFunction(_ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE, MSHake(_ZNK7WebCore19MediaQueryEvaluator4evalEPKNS_13MediaQueryExpE));
+
+ void *(*_ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE)(WebCore::MediaQueryExp *, WebCore::String &, WebCore::CSSParserValueList *);
+ msset(_ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE, WebCore);
+ if (_ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE != NULL)
+ MSHookFunction(_ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE, MSHake(_ZN7WebCore13MediaQueryExpC2ERKN3WTF12AtomicStringEPNS_18CSSParserValueListE));
+}
+
+MSClassHook(WebView)
+MSMetaClassHook(WebView)
+
+MSClassMessageHook0(void, WebView, enableWebThread) {
+ if (kCFCoreFoundationVersionNumber >= 478.61)
+ return MSOldCall();
+
+ NSLog(@"-[WebView enableWebThread]");
+}