2015-02-13 6 views
0

Я пишу код iOS для аутентификации с помощью прокси-сервера HTTPS, и для создания заголовка «Прокси-авторизация» необходимо использовать API-интерфейсы Core Foundation. Однако я заблокирован, пытаясь создать действительный объект CFHTTPAuthenticationRef.CFHTTPAuthenticationCreateFromResponse не удается проанализировать ответ

После получения ответа на запрос «407 Proxy authentication required» с заголовком «Proxy-Authenticate: Basic realm =» example.com, я вызываю CFHTTPAuthenticationCreateFromResponse. Это возвращает недопустимый объект CFHTTPAuthenticationRef; ошибка равна -1000, или kCFStreamErrorHTTPAuthenticationTypeUsupported.

От взгляда на очень устаревший исходный код, доступный на http://www.opensource.apple.com/source/CFNetwork/CFNetwork-129.20/HTTP/CFHTTPAuthentication.c, все это должно работать нормально. Я проверил в отладчике, что некоторые внутренние структуры, такие как _схемы, на самом деле разбираются правильно, поэтому я знаю, что значение моего заголовка верное. Очевидно, что код внутри CFHTTPAuthenticationCreateFromResponse изменился, но я не понимаю, что мне нужно сделать, чтобы сделать эту работу.

Отступая через код сборки, похоже, что это может быть связано с отсутствием URL-адреса. Нет публичного API для добавления URL-адреса в ответ, и тот факт, что он не нужен для аутентификации Basic и Digest, является нечетным.

Я наблюдал это на OSX Mavericks, симуляторе iOS 7 и симуляторе iOS 8. Я проглотил это до простой функции воспроизведения, вставленной ниже. Я также пробовал использовать тестовый прокси-сервер и CFReadStream, создавая ответ от CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader), безрезультатно (что, предположительно, ассоциировало бы URL-адрес с объектом ответа).

void testCFAuthentication() 
{ 
    Boolean result; 
    CFStringRef str; 
    const char *rawResponse = "HTTP/1.1 407 Proxy authentication required\r\nProxy-Authenticate: Basic realm=\"example.com\"\r\n\r\n"; 

    CFHTTPMessageRef responseMessage = NULL; 
    responseMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false); 

    // Optional hack, doesn't help 
    /* 
    CFURLRef url = NULL; 
    url = CFURLCreateWithString(NULL, CFSTR("https://example.com/"), NULL); 
    _CFHTTPMessageSetResponseURL(responseMessage, url); 
    NSLog(@"_CFHTTPMessageSetResponseURL called\n"); 
    */ 

    result = CFHTTPMessageAppendBytes(responseMessage, (uint8_t *)rawResponse, strlen(rawResponse)); 
    NSLog(@"CFHTTPMessageAppendBytes result: %d\n", (int)result); 
    NSLog(@"CFHTTPMessageIsHeaderComplete: %d\n", (int)CFHTTPMessageIsHeaderComplete(responseMessage)); 
    NSLog(@"CFHTTPMessageGetResponseStatusCode: %d\n", (int)CFHTTPMessageGetResponseStatusCode(responseMessage)); 
    NSLog(@"CFHTTPMessageCopyResponseStatusLine: %s\n", CFStringGetCStringPtr(CFHTTPMessageCopyResponseStatusLine(responseMessage), kCFStringEncodingUTF8)); 
    NSLog(@"Proxy-Authenticate header value: %s\n", CFStringGetCStringPtr(CFHTTPMessageCopyHeaderFieldValue(responseMessage, CFSTR("Proxy-Authenticate")), kCFStringEncodingUTF8)); 

    CFHTTPAuthenticationRef auth = NULL; 
    auth = CFHTTPAuthenticationCreateFromResponse(NULL, responseMessage); 
    NSLog(@"CFHTTPAuthenticationCreateFromResponse:\n"); CFShow(auth); 
    if (auth) { 
     CFStreamError error = { 0 }; 
     result = CFHTTPAuthenticationIsValid(auth, &error); 
     if (!result) { 
      NSLog(@"CFHTTPAuthenticationIsValid: false, error %d (0x%x), domain %ld (0x%lx)\n", error.error, error.error, error.domain, error.domain); 
     } else { 
      NSLog(@"CFHTTPAuthenticationCopyMethod=%s\n", CFStringGetCStringPtr(CFHTTPAuthenticationCopyMethod(auth), kCFStringEncodingUTF8)); 
      NSLog(@"authRealm=%s\n", CFStringGetCStringPtr(CFHTTPAuthenticationCopyRealm(auth), kCFStringEncodingUTF8)); 
     } 
    }; 
} 

Выход:

2015-02-13 11:01:05.654 CFHTTPMessageAppendBytes result: 1 
2015-02-13 11:01:05.655 CFHTTPMessageIsHeaderComplete: 1 
2015-02-13 11:01:05.656 CFHTTPMessageGetResponseStatusCode: 407 
2015-02-13 11:01:05.657 CFHTTPMessageCopyResponseStatusLine: HTTP/1.1 407 Proxy authentication required 
2015-02-13 11:01:05.657 Proxy-Authenticate header value: Basic realm="example.com" 
2015-02-13 11:01:05.658 CFHTTPAuthenticationCreateFromResponse: 
<CFHTTPAuthentication 0x7fe0d36017f0>{state = Failed; scheme = <undecided>, forProxy = true} 
2015-02-13 11:01:05.658 CFHTTPAuthenticationIsValid: false, error -1000 (0xfffffc18), domain 4 (0x4) 

ответ

0

Вы сталкиваетесь same problem as I, но в несколько иной вкус. Проблема в том, что CFHTTPAuthenticationCreateFromResponse работает только с ответом, полученным от CFHTTPStream. Я нашел решение, см. my answer.

Expose private API (это приведет к отказу от Apple).

// exposing private API for workaround 
extern void _CFHTTPMessageSetResponseURL(CFHTTPMessageRef, CFURLRef); 

Добавить добавить URL в ответ, используя этот частный API:

_CFHTTPMessageSetResponseURL(responseMessage, 
          (__bridge CFURLRef)[NSURL URLWithString: "https://example.com/"]); 
auth = CFHTTPAuthenticationCreateFromResponse(NULL, responseMessage); 
Смежные вопросы