Make http keepalive for GSHTTPURLHandle more robust.

This commit is contained in:
Richard Frith-Macdonald 2022-10-18 18:01:02 +01:00
parent ff4ade98ae
commit 726d24bac7
2 changed files with 71 additions and 6 deletions

View file

@ -1,3 +1,16 @@
2022-10-18 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSHTTPURLHandle.m: Track whether we have read any data from
the server. If a connection is closed by the server while it is being
kept alive (ie we are not on first request) and no response data has
been read for a request we sent, we assume it was an intentional close
and try to establish a new connection to retry the request.
This is more tolerant of latency in the network (which could mean that
our test tthat the connection is still alive before sending a request
could be wrong) and also deals with perverse server implementations
which drop long standing connections when the server receives a
request rather than when a timeout occurred.
2022-09-15 Hugo Melder <contact@hugomelder.com>
* config/config.constant-string-class.m:

View file

@ -113,6 +113,7 @@ static NSString *httpVersion = @"1.1";
BOOL debug;
BOOL keepalive;
BOOL returnAll;
BOOL inResponse;
id<GSLogDelegate> ioDelegate;
unsigned char challenged;
NSFileHandle *sock;
@ -703,8 +704,31 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
[sock closeFile];
DESTROY(sock);
}
else if (0 == readCount && NO == inResponse && YES == keepalive)
{
/* On a keepalive connection where the remote end
* dropped the connection without responding. We
* should try again.
*/
if (connectionState != idle)
{
[nc removeObserver: self name: nil object: sock];
[sock closeFile];
DESTROY(sock);
DESTROY(in);
DESTROY(out);
connectionState = idle;
if (debug)
{
NSLog(@"%@ %p restart on new connection",
NSStringFromSelector(_cmd), self);
}
[self _tryLoadInBackground: u];
}
}
else if ([parser parse: d] == NO && [parser isComplete] == NO)
{
inResponse = YES;
if (debug)
{
NSLog(@"HTTP parse failure - %@", parser);
@ -714,8 +738,10 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
}
else
{
BOOL complete = [parser isComplete];
BOOL complete;
inResponse = YES;
complete = [parser isComplete];
if (complete == NO && [parser isInHeaders] == NO)
{
GSMimeHeader *info;
@ -960,7 +986,8 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
NSDictionary *dict = [not userInfo];
NSData *d;
GSMimeParser *p = [GSMimeParser new];
GSMimeParser *p;
unsigned readCount;
RETAIN(self);
if (debug)
@ -968,6 +995,7 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
NSLog(@"%@ %p %s", NSStringFromSelector(_cmd), self, keepalive?"K":"");
}
d = [dict objectForKey: NSFileHandleNotificationDataItem];
readCount = [d length];
if (debug)
{
if (NO == [ioDelegate getBytes: [d bytes]
@ -978,10 +1006,32 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
}
}
if ([d length] > 0)
if (readCount > 0)
{
inResponse = YES;
[dat appendData: d];
}
else if (NO == inResponse)
{
/* remote end dropped the connection without responding
*/
[nc removeObserver: self name: nil object: sock];
[sock closeFile];
DESTROY(sock);
DESTROY(in);
DESTROY(out);
connectionState = idle;
if (debug)
{
NSLog(@"%@ %p restart on new connection",
NSStringFromSelector(_cmd), self);
}
[self _tryLoadInBackground: u];
DESTROY(self);
return;
}
p = [GSMimeParser new];
[p parse: dat];
if ([p isInBody] == YES || [d length] == 0)
{
@ -1297,7 +1347,6 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
}
[self _apply];
}
- (void) bgdHandshake: (NSNotification*)notification
@ -1359,8 +1408,10 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
DESTROY(out);
connectionState = idle;
if (debug)
NSLog(@"%@ %p restart on new connection",
NSStringFromSelector(_cmd), self);
{
NSLog(@"%@ %p restart on new connection",
NSStringFromSelector(_cmd), self);
}
[self _tryLoadInBackground: u];
RELEASE(self);
return;
@ -1554,6 +1605,7 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
return;
}
inResponse = NO;
[dat setLength: 0];
RELEASE(document);
RELEASE(parser);