iOS 4.x と、5.x では、NSURLProtocol の SSL認証時 / BASIC認証時の実行メソッドが異なる。
iOS 4.x では、、、
canAuthenticateAgainstProtectionSpace → didReceiveAuthenticationChallenge
iOS 5.x では、、、
canAuthenticateAgainstProtectionSpace → willSendRequestForAuthenticationChallenge
であるので、両方のバージョンサポートは工夫が必要
#pragma mark == NSURLProtocolオブジェクトの初期化 ==
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client
{
NSMutableURLRequest* aRequest = [ request mutableCopy ];
[ aRequest setAllHTTPHeaderFields:[ request allHTTPHeaderFields]];
[ aRequest setValue: kFenicsBrowserHeaderValueforHTTPHeaderField: kFenicsBrowserHeader ];
self = [ super initWithRequest: aRequest cachedResponse:cachedResponse client: client ];
if ( self )
{
self.protocolRequest = aRequest;
}
[ aRequest release ];
aRequest = nil;
returnself;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
NSString* strVersion = [[UIDevice currentDevice] systemVersion];
double version = [strVersion doubleValue];
DLog(@"## OS Version %1.2f", version);
return YES;
}
#pragma -
#pragma mark *** 認証の必要なページにアクセスしたとき iOS 4,x **********************
- ( void ) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
self.myChallenge = challenge;
[self authProcess:challenge];
}
#pragma mark *** 認証の必要なページにアクセスしたとき iOS 5.x **********************
static BOOL isSSL_CONFIRM;
-( void ) connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString* strVersion = [[UIDevice currentDevice] systemVersion];
double version = [strVersion doubleValue];
DLog(@"## OS Version %1.2f", version);
self.myChallenge = challenge;
[self authProcess:challenge];
}
#pragma mark -------------- 認証用プロセス OS共通 -----------------
-(void)authProcess:(NSURLAuthenticationChallenge *)challenge
{
isSSL_CONFIRM = YES;
if ([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodHTTPBasic]
|| [challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodHTTPDigest]) {
// BASIC/DIGEST認証が必要
isSSL_CONFIRM = NO;
[selfperformSelectorOnMainThread:@selector(challengeBasic) withObject:nilwaitUntilDone:YES];
return;
}elseif([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodServerTrust]){
// SSL認証時
NSLog(@"# NSURLAuthentication URL = %@", [[self.requestURL] absoluteString] );
NSURLResponse *checkresponse;
NSError *error = nil;
[ NSURLConnectionsendSynchronousRequest:self.request
returningResponse:&checkresponse
error:&error ];
if (error==nil) {
// 事前チェックでエラーなし
[challenge.senderuseCredential:[NSURLCredentialcredentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
[challenge.sendercontinueWithoutCredentialForAuthenticationChallenge:challenge];
}else{
NSLog(@"# SSL error code = %d", [error code]);
if ([error code]==NSURLErrorServerCertificateHasUnknownRoot){
[selfchallengSSL:[NSStringstringWithFormat:@"%@ %@",@"SSL認証に問題があります", @"Certificate has Unknown Root"]];
//
// SSL エラーなどを記述
//
}else if ([error code]==NSURLErrorTimedOut){
// iOS 4.x は、UIWebView の didFailLoadWithError ではなく、ここでハンドルされる。
}else{
//
}
}
}
}
#pragma mark --- BASIC認証ダイアログ表示 ---
-(void)challengeBasic
{
NSString* strVersion = [[UIDevice currentDevice] systemVersion];
double version = [strVersion doubleValue];
if (version >= 5.0) {
// iOS 5.0 ~
UIAlertView *dialog = [[UIAlertViewalloc] initWithTitle:@"認証が必要です"
message:@""
delegate:self
cancelButtonTitle:@"cancel"
otherButtonTitles:@"OK", nil ];
[dialog setAlertViewStyle: UIAlertViewStyleLoginAndPasswordInput];
[dialog show];
[dialog autorelease];
}else {
// iOS 4.x は、UIAlertViewStyleLoginAndPasswordInput が使えないので
// 上とは別の方法でダイアログを表示する必要がある。
}
}
#pragma mark --- SSL警告ダイアログ ------
-(void)challengSSL:(NSString*)message
{
UIAlertView *dialog = [[UIAlertViewalloc] initWithTitle:nil
message:message
delegate:self
cancelButtonTitle:@"cancel"
otherButtonTitles:@"done", nil ];
[dialog show];
[dialog autorelease];
}
#pragma mark ==== ダイアログボタン押したインデックス====
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString* strVersion = [[UIDevice currentDevice] systemVersion];
double version = [strVersion doubleValue];
if (isSSL_CONFIRM){
switch (buttonIndex) {
case 0: // キャンセル
[[self.myChallengesender] cancelAuthenticationChallenge:self.myChallenge];
if (version >= 5.0) {
[ self.protocolConnection cancel ];
}
break;
case 1: // GO
[self.myChallenge.senderuseCredential:[NSURLCredentialcredentialForTrust:self.myChallenge.protectionSpace.serverTrust]
forAuthenticationChallenge:self.myChallenge];
[[self.myChallengesender] continueWithoutCredentialForAuthenticationChallenge:self.myChallenge];
break;
}
}else {
switch (buttonIndex) {
case 0: // キャンセル
[[self.myChallengesender] cancelAuthenticationChallenge:self.myChallenge];
[ self.protocolConnection cancel ];
break;
case 1: // GO
;
UITextField *username = [alertView textFieldAtIndex:0];
UITextField *password = [alertView textFieldAtIndex:1];
NSURLCredential* credential = [NSURLCredentialcredentialWithUser:username.textpassword:password.textpersistence:NSURLCredentialPersistenceForSession];
[[self.myChallengesender] useCredential:credential forAuthenticationChallenge:self.myChallenge];
// webview で、stopLoading すべき!!
break;
}
}
}
#pragma mark ----- リダイレクトのハンドリング -----
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
{
NSMutableURLRequest* mrequest = [[request mutableCopy] autorelease];
if (redirectResponse){
NSLog(@"# Redirect URL = %@", [request.URL absoluteString]);
[ mrequest setValue:nilforHTTPHeaderField:kFenicsBrowserHeader];
[[selfclient] URLProtocol:selfwasRedirectedToRequest: mrequest redirectResponse:redirectResponse];
self.protocolRequest = mrequest;
self.protocolResponse = ( NSHTTPURLResponse* )redirectResponse;
return mrequest;
}
self.protocolRequest = mrequest;
self.protocolResponse = ( NSHTTPURLResponse* )redirectResponse;
return aRequest;
}
#pragma mark *** 通信エラーが発生したとき ***
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[[selfclient] URLProtocol:selfdidFailWithError:error];
self.protocolConnection = nil;
}
- ( void ) notifyResponse
{
NSHTTPURLResponse* res = [ [ self.protocolResponse copy ] autorelease ];
NSMutableDictionary* dic = [ NSMutableDictionary dictionaryWithObject: res forKey: @"HTTP_RESPONSE" ];
NSNotification* n = [ NSNotificationnotificationWithName: kHttpResponseReceivedobject: selfuserInfo: dic ];
[ [ NSNotificationCenterdefaultCenter ] postNotification: n ];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
- (NSString *)cachePathForRequest:(NSURLRequest *)aRequest
{
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
return [cachesPath stringByAppendingPathComponent:[NSStringstringWithFormat:@"%x", [[[aRequest URL] absoluteString] hash]]];
}