ObjFW  Diff

Differences From Artifact [97ab76e832]:

To Artifact [95811098ef]:


324
325
326
327
328
329
330
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338
339
340
341
342






343
344
345
346
347
348
349







-
+











-
-
-
-
-
-







{
	void *pool = objc_autoreleasePoolPush();
	OFURL *URL = [request URL];
	OFString *scheme = [URL scheme];
	of_http_request_method_t method = [request method];
	OFMutableString *requestString;
	OFDictionary *headers = [request headers];
	OFDataArray *POSTData = [request POSTData];
	OFDataArray *entity = [request entity];
	OFTCPSocket *socket;
	OFHTTPClientResponse *response;
	OFString *line, *path, *version, *redirect, *keepAlive;
	OFMutableDictionary *serverHeaders;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	OFString *key, *object;
	int status;

	if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"])
		@throw [OFUnsupportedProtocolException exceptionWithURL: URL];

	if (method != OF_HTTP_REQUEST_METHOD_GET &&
	    method != OF_HTTP_REQUEST_METHOD_HEAD &&
	    method != OF_HTTP_REQUEST_METHOD_POST)
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	/* Can we reuse the socket? */
	if (_socket != nil && [[_lastURL scheme] isEqual: [URL scheme]] &&
	    [[_lastURL host] isEqual: [URL host]] &&
	    [_lastURL port] == [URL port]) {
		/*
		 * Set _socket to nil, so that in case of an error it won't be
		 * reused. If everything is successfull, we set _socket again
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466




467
468
469
470
471
472
473
401
402
403
404
405
406
407













408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424



425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443




444
445
446
447
448
449
450
451
452
453
454







-
-
-
-
-
-
-
-
-
-
-
-
-

















-
-
-
+
+
+
















-
-
-
-
+
+
+
+







	keyEnumerator = [headers keyEnumerator];
	objectEnumerator = [headers objectEnumerator];

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil)
		[requestString appendFormat: @"%@: %@\r\n", key, object];

	if (method == OF_HTTP_REQUEST_METHOD_POST) {
		OFString *contentType = [request MIMEType];

		if (contentType == nil)
			contentType = @"application/x-www-form-urlencoded; "
			    @"charset=UTF-8";

		[requestString appendFormat:
		    @"Content-Type: %@\r\n"
		    @"Content-Length: %zu\r\n",
		    contentType, [POSTData count] * [POSTData itemSize]];
	}

	if ([request protocolVersion].major == 1 &&
	    [request protocolVersion].minor == 0)
		[requestString appendString: @"Connection: keep-alive\r\n"];

	[requestString appendString: @"\r\n"];

	@try {
		[socket writeString: requestString];
	} @catch (OFWriteFailedException *e) {
		if ([e errNo] != ECONNRESET && [e errNo] != EPIPE)
			@throw e;

		/* Reconnect in case a keep-alive connection timed out */
		socket = [self OF_createSocketForRequest: request];
		[socket writeString: requestString];
	}

	if (method == OF_HTTP_REQUEST_METHOD_POST)
		[socket writeBuffer: [POSTData items]
			     length: [POSTData count] * [POSTData itemSize]];
	if (entity != nil)
		[socket writeBuffer: [entity items]
			     length: [entity count] * [entity itemSize]];

	@try {
		line = [socket readLine];
	} @catch (OFInvalidEncodingException *e) {
		@throw [OFInvalidServerReplyException exception];
	}

	/*
	 * It's possible that the write succeeds on a connection that is
	 * keep-alive, but the connection has already been closed by the remote
	 * end due to a timeout. In this case, we need to reconnect.
	 */
	if (line == nil) {
		socket = [self OF_createSocketForRequest: request];
		[socket writeString: requestString];

		if (method == OF_HTTP_REQUEST_METHOD_POST)
			[socket writeBuffer: [POSTData items]
				     length: [POSTData count] *
					     [POSTData itemSize]];
		if (entity != nil)
			[socket writeBuffer: [entity items]
				     length: [entity count] *
					     [entity itemSize]];

		@try {
			line = [socket readLine];
		} @catch (OFInvalidEncodingException *e) {
			@throw [OFInvalidServerReplyException exception];
		}
	}
576
577
578
579
580
581
582
583

584
585
586















587
588
589
590


591
592
593
594
595
596
597
557
558
559
560
561
562
563

564

565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583


584
585
586
587
588
589
590
591
592







-
+
-


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
-
+
+








		if (follow) {
			OFHTTPRequest *newRequest;

			newRequest = [OFHTTPRequest requestWithURL: newURL];
			[newRequest setMethod: method];
			[newRequest setHeaders: headers];
			[newRequest setPOSTData: POSTData];
			[newRequest setEntity: entity];
			[newRequest setMIMEType: [request MIMEType]];

			if (status == 303) {
				OFMutableDictionary *newHeaders;
				OFEnumerator *keyEnumerator, *objectEnumerator;
				id key, object;

				newHeaders = [OFMutableDictionary dictionary];
				keyEnumerator = [headers keyEnumerator];
				objectEnumerator = [headers objectEnumerator];
				while ((key = [keyEnumerator nextObject]) !=
				    nil &&
				    (object = [objectEnumerator nextObject]) !=
				    nil)
					if (![key hasPrefix: @"Content-"])
						[newHeaders setObject: object
							       forKey: key];

				[newRequest
				    setMethod: OF_HTTP_REQUEST_METHOD_GET];
				[newRequest setPOSTData: nil];
				[newRequest setMIMEType: nil];
				[newRequest setHeaders: newHeaders];
				[newRequest setEntity: nil];
			}

			[newRequest retain];
			objc_autoreleasePoolPop(pool);
			[newRequest autorelease];

			return [self performRequest: newRequest