Я пишу код 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)