Я занимаюсь разработкой веб-прокси для использования с iOS и OSX с использованием библиотеки cocoaAsyncSocket и столкнулся с проблемой.Я могу принять несколько подключений от клиента, проанализировать заголовки, подключиться к месту назначения через порт 80/443 и начать получать данные, одновременно передавая данные обратно в сокет клиента.Однако у меня проблема в том, что серверный сокет закрывается перед завершением чтения содержимого при использовании метода readDataToLength: x, однако, если я просто использую readDataWithTimeout, все в порядке, и страница будет загружаться.
Использование curlчерез мой прокси я вижу, что данные частично получены, но соединение закрывается с
transfer closed with 12 bytes remaining to read
* stopped the pause stream!
* Closing connection 0
curl: (18) transfer closed with 12 bytes remaining to read
Однако метод делегата
socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
сообщает мне, что он завершил частичное чтение 12 байтовтак что может показаться, что чтение завершено.
-(void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
NSLog(@"READ PARTIAL DATA %lu with tag: %lu",partialLength, tag);
[sock readDataToLength:partialLength withTimeout:3 tag:tag];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
ConnectionData *socketData;
@synchronized (self) {
socketData = [self getConnectionDataForSocket:sock];
}
if (tag == CLIENT_SOCK_READ) {
//NSLog(@"READ FROM CLIENT");
if (!socketData.serverSocket){
//We dont have a server socket yet, assume that we are reading the header data.
NSString *headers = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
//Decide if we have a http or ssl connection
if ([headers containsString:@"CONNECT"]) {
//TLS SESSION
NSString* hostToConnect = [self extractStringFromString:headers from:@"CONNECT " to:@":"];
NSError *connectError;
GCDAsyncSocket *serverSock = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:[self socketsDispatchQueue]];
@synchronized (self) {
socketData.serverSocket = serverSock;
}
if (![serverSock connectToHost:hostToConnect onPort:443 withTimeout:10 error:&connectError]){
NSLog(@"Failed to connect to host: %@", [connectError debugDescription]);
}
NSString *tlsClientResponse = @"HTTP/1.0 200 Connection established\r\n\r\n";
[[socketData clientSocket]writeData:[tlsClientResponse dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:CLIENT_SOCK_WRITE];
} else {
NSString *hostToConnect = [self extractStringFromString:headers from:@"http://" to:@"/"];
NSString *newheaderLine = [self prepareHttpHeader:headers];
//Rewite headers
NSError *connectError;
GCDAsyncSocket *serverSock = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:[self socketsDispatchQueue]];
@synchronized (self) {
socketData.serverSocket = serverSock;
}
if (![serverSock connectToHost:hostToConnect onPort:80 withTimeout:10 error:&connectError]){
NSLog(@"Failed to connect to host: %@", [connectError debugDescription]);
}
[socketData.serverSocket writeData:[newheaderLine dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:false] withTimeout:10 tag:SERVER_SOCK_WRITE];
}
} else {
[socketData.serverSocket writeData:data withTimeout:3 tag:SERVER_SOCK_WRITE];
}
} else if (tag == SERVER_SOCK_READ){
[socketData.serverSocket readDataToLength:25 withTimeout:3 tag:SERVER_SOCK_READ];
[socketData.clientSocket writeData:data withTimeout:3 tag:CLIENT_SOCK_WRITE];
}
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
ConnectionData *socketData;
@synchronized (self) {
socketData = [self getConnectionDataForSocket:sock];
}
if (tag == SERVER_SOCK_WRITE){
[socketData.serverSocket readDataToLength:25 withTimeout:3 tag:SERVER_SOCK_READ];
} else if (tag == CLIENT_SOCK_WRITE){
[socketData.clientSocket readDataToLength:25 withTimeout:3 tag:CLIENT_SOCK_READ];
[socketData.serverSocket readDataToLength:25 withTimeout:3 tag:SERVER_SOCK_READ];
}
}
Я ожидал, что чтение завершится в сокете перед закрытием, как это происходит, когда я вызываю readDataWithTimeout, если кто-нибудь может указать мне правильное направление, еслиочень благодарен!