ObjFW  Check-in [958da109d3]

Overview
Comment:Support for passing a context to async IO handlers
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 958da109d3850e09d02d50cecc25ef17abf5b1c2eb42df05ac353b89cad27528
User & Date: js on 2017-09-23 22:07:34
Other Links: manifest | tags
Context
2017-09-24
00:59
Make OFHTTPClient asynchronous check-in: 56a18442e2 user: js tags: trunk
2017-09-23
22:07
Support for passing a context to async IO handlers check-in: 958da109d3 user: js tags: trunk
20:35
ofhttp: Refactor for asynchronous OFHTTPClient check-in: c26c8ca746 user: js tags: trunk
Changes

Modified src/OFHTTPServer.m from [c477e44d18] to [f88ae06cce].

45
46
47
48
49
50
51

52
53
54
55
56
57
58
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59







+







 * FIXME: Key normalization replaces headers like "DNT" with "Dnt".
 * FIXME: Errors are not reported to the user.
 */

@interface OFHTTPServer ()
- (bool)of_socket: (OFTCPSocket *)socket
  didAcceptSocket: (OFTCPSocket *)clientSocket
	  context: (id)context
	exception: (OFException *)exception;
@end

static const char *
statusCodeToString(short code)
{
	switch (code) {
338
339
340
341
342
343
344

345
346
347
348
349
350

351
352
353
354
355
356
357
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360







+






+







	OFMutableData *_body;
}

- initWithSocket: (OFTCPSocket *)socket
	  server: (OFHTTPServer *)server;
- (bool)socket: (OFTCPSocket *)socket
   didReadLine: (OFString *)line
       context: (id)context
     exception: (OFException *)exception;
- (bool)parseProlog: (OFString *)line;
- (bool)parseHeaders: (OFString *)line;
-      (bool)socket: (OFTCPSocket *)socket
  didReadIntoBuffer: (char *)buffer
	     length: (size_t)length
	    context: (id)context
	  exception: (OFException *)exception;
- (bool)sendErrorAndClose: (short)statusCode;
- (void)createResponse;
@end

@implementation OFHTTPServer_Connection
- initWithSocket: (OFTCPSocket *)socket
391
392
393
394
395
396
397

398
399
400
401
402
403
404
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408







+







	[_body release];

	[super dealloc];
}

- (bool)socket: (OFTCPSocket *)socket
   didReadLine: (OFString *)line
       context: (id)context
     exception: (OFException *)exception
{
	if (line == nil || exception != nil)
		return false;

	@try {
		switch (_state) {
503
504
505
506
507
508
509

510


511
512
513
514
515
516
517
507
508
509
510
511
512
513
514

515
516
517
518
519
520
521
522
523







+
-
+
+







			_body = [[OFMutableData alloc] init];

			[_socket asyncReadIntoBuffer: buffer
					      length: BUFFER_SIZE
					      target: self
					    selector: @selector(socket:
							  didReadIntoBuffer:
							  length:context:
							  length:exception:)];
							  exception:)
					     context: nil];
			[_timer setFireDate:
			    [OFDate dateWithTimeIntervalSinceNow: 5]];

			return false;
		}

		_state = SEND_RESPONSE;
568
569
570
571
572
573
574

575
576
577
578
579
580
581
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588







+








	return true;
}

-      (bool)socket: (OFTCPSocket *)socket
  didReadIntoBuffer: (char *)buffer
	     length: (size_t)length
	    context: (id)context
	  exception: (OFException *)exception
{
	if ([socket isAtEndOfStream] || exception != nil)
		return false;

	[_body addItems: buffer
		  count: length];
718
719
720
721
722
723
724
725
726



727
728
729
730
731
732
733
734
735
736
737

738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757


758
759
760
761
725
726
727
728
729
730
731


732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765

766
767
768
769
770
771







-
-
+
+
+











+



















-
+
+




	_listeningSocket = [[OFTCPSocket alloc] init];
	_port = [_listeningSocket bindToHost: _host
					port: _port];
	[_listeningSocket listen];

	[_listeningSocket asyncAcceptWithTarget: self
				       selector: @selector(of_socket:
						     didAcceptSocket:
						     exception:)];
						     didAcceptSocket:context:
						     exception:)
					context: nil];
}

- (void)stop
{
	[_listeningSocket cancelAsyncRequests];
	[_listeningSocket release];
	_listeningSocket = nil;
}

- (bool)of_socket: (OFTCPSocket *)socket
  didAcceptSocket: (OFTCPSocket *)clientSocket
	  context: (id)context
	exception: (OFException *)exception
{
	OFHTTPServer_Connection *connection;

	if (exception != nil) {
		if ([_delegate respondsToSelector:
		    @selector(server:didReceiveExceptionOnListeningSocket:)])
			return [_delegate		  server: self
			    didReceiveExceptionOnListeningSocket: exception];

		return false;
	}

	connection = [[[OFHTTPServer_Connection alloc]
	    initWithSocket: clientSocket
		    server: self] autorelease];

	[clientSocket asyncReadLineWithTarget: connection
				     selector: @selector(socket:didReadLine:
						  exception:)];
						  context:exception:)
				      context: nil];

	return true;
}
@end

Modified src/OFRunLoop+Private.h from [6cb34b1a9e] to [d3aaadeae6].

25
26
27
28
29
30
31
32


33
34
35
36
37


38
39
40
41


42
43
44


45
46
47
48
49


50
51
52
53
54
55
56
25
26
27
28
29
30
31

32
33
34
35
36
37

38
39
40
41
42

43
44
45
46

47
48
49
50
51
52

53
54
55
56
57
58
59
60
61







-
+
+




-
+
+



-
+
+


-
+
+




-
+
+







@interface OFRunLoop ()
+ (void)of_setMainRunLoop: (OFRunLoop *)runLoop;
#ifdef OF_HAVE_SOCKETS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
			  length: (size_t)length
			  target: (id)target
			selector: (SEL)selector;
			selector: (SEL)selector
			 context: (nullable id)context;
+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
		     exactLength: (size_t)length
			  target: (id)target
			selector: (SEL)selector;
			selector: (SEL)selector
			 context: (nullable id)context;
+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
			    encoding: (of_string_encoding_t)encoding
			      target: (id)target
			    selector: (SEL)selector;
			    selector: (SEL)selector
			     context: (nullable id)context;
+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)socket
			       target: (id)target
			     selector: (SEL)selector;
			     selector: (SEL)selector
			      context: (nullable id)context;
+ (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket
				buffer: (void *)buffer
				length: (size_t)length
				target: (id)target
			      selector: (SEL)selector;
			      selector: (SEL)selector
			       context: (nullable id)context;
# ifdef OF_HAVE_BLOCKS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
			  length: (size_t)length
			   block: (of_stream_async_read_block_t)block;
+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer

Modified src/OFRunLoop.m from [2bcc651795] to [35d1810bb5].

41
42
43
44
45
46
47

48
49
50
51
52
53
54
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55







+








#ifdef OF_HAVE_SOCKETS
@interface OFRunLoop_QueueItem: OFObject
{
@public
	id _target;
	SEL _selector;
	id _context;
}

- (bool)handleForObject: (id)object;
@end

@interface OFRunLoop_ReadQueueItem: OFRunLoop_QueueItem
{
107
108
109
110
111
112
113

114
115
116
117
118
119
120
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122







+







{
	OF_UNRECOGNIZED_SELECTOR
}

- (void)dealloc
{
	[_target release];
	[_context release];

	[super dealloc];
}
@end

@implementation OFRunLoop_ReadQueueItem
- (bool)handleForObject: (id)object
131
132
133
134
135
136
137
138

139
140

141
142
143
144

145
146
147
148
149
150
151
133
134
135
136
137
138
139

140
141

142
143
144
145

146
147
148
149
150
151
152
153







-
+

-
+



-
+







	}

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		return _block(object, _buffer, length, exception);
	else {
# endif
		bool (*func)(id, SEL, OFStream *, void *, size_t,
		bool (*func)(id, SEL, OFStream *, void *, size_t, id,
		    OFException *) = (bool (*)(id, SEL, OFStream *, void *,
		    size_t, OFException *))
		    size_t, id, OFException *))
		    [_target methodForSelector: _selector];

		return func(_target, _selector, object, _buffer, length,
		    exception);
		    _context, exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

# ifdef OF_HAVE_BLOCKS
- (void)dealloc
182
183
184
185
186
187
188
189

190
191

192
193
194
195

196
197
198
199
200
201
202
184
185
186
187
188
189
190

191
192

193
194
195
196

197
198
199
200
201
202
203
204







-
+

-
+



-
+







		if (!_block(object, _buffer, _readLength, exception))
			return false;

		_readLength = 0;
		return true;
	} else {
# endif
		bool (*func)(id, SEL, OFStream *, void *, size_t,
		bool (*func)(id, SEL, OFStream *, void *, size_t, id,
		    OFException *) = (bool (*)(id, SEL, OFStream *, void *,
		    size_t, OFException *))
		    size_t, id, OFException *))
		    [_target methodForSelector: _selector];

		if (!func(_target, _selector, object, _buffer, _readLength,
		    exception))
		    _context, exception))
			return false;

		_readLength = 0;
		return true;
# ifdef OF_HAVE_BLOCKS
	}
# endif
229
230
231
232
233
234
235
236
237
238



239
240


241
242
243
244
245
246
247
231
232
233
234
235
236
237



238
239
240
241

242
243
244
245
246
247
248
249
250







-
-
-
+
+
+

-
+
+







		return true;

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		return _block(object, line, exception);
	else {
# endif
		bool (*func)(id, SEL, OFStream *, OFString *, OFException *) =
		    (bool (*)(id, SEL, OFStream *, OFString *, OFException *))
		    [_target methodForSelector: _selector];
		bool (*func)(id, SEL, OFStream *, OFString *, id,
		    OFException *) = (bool (*)(id, SEL, OFStream *, OFString *,
		    id, OFException *))[_target methodForSelector: _selector];

		return func(_target, _selector, object, line, exception);
		return func(_target, _selector, object, line, _context,
		    exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

# ifdef OF_HAVE_BLOCKS
- (void)dealloc
267
268
269
270
271
272
273
274

275
276

277
278
279


280
281
282
283
284
285
286
270
271
272
273
274
275
276

277
278

279
280
281

282
283
284
285
286
287
288
289
290







-
+

-
+


-
+
+







	}

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		return _block(object, newSocket, exception);
	else {
# endif
		bool (*func)(id, SEL, OFTCPSocket *, OFTCPSocket *,
		bool (*func)(id, SEL, OFTCPSocket *, OFTCPSocket *, id,
		    OFException *) = (bool (*)(id, SEL, OFTCPSocket *,
		    OFTCPSocket *, OFException *))
		    OFTCPSocket *, id, OFException *))
		    [_target methodForSelector: _selector];

		return func(_target, _selector, object, newSocket, exception);
		return func(_target, _selector, object, newSocket, _context,
		    exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

# ifdef OF_HAVE_BLOCKS
- (void)dealloc
310
311
312
313
314
315
316
317

318
319

320
321
322
323

324
325
326
327
328
329
330
314
315
316
317
318
319
320

321
322

323
324
325
326

327
328
329
330
331
332
333
334







-
+

-
+



-
+








# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		return _block(object, _buffer, length, address, exception);
	else {
# endif
		bool (*func)(id, SEL, OFUDPSocket *, void *, size_t,
		    of_udp_socket_address_t address, OFException *) =
		    of_udp_socket_address_t address, id, OFException *) =
		    (bool (*)(id, SEL, OFUDPSocket *, void *, size_t,
		    of_udp_socket_address_t, OFException *))
		    of_udp_socket_address_t, id, OFException *))
		    [_target methodForSelector: _selector];

		return func(_target, _selector, object, _buffer, length,
		    address, exception);
		    address, _context, exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

# ifdef OF_HAVE_BLOCKS
- (void)dealloc
381
382
383
384
385
386
387

388
389
390
391

392
393
394
395
396
397
398
399
400
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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
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
455
456
457
458
459
460
461
462
463
464







+




+










+




+









+




+







+




+








+


-
-


+
+
+







	objc_autoreleasePoolPop(pool);

+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
			  length: (size_t)length
			  target: (id)target
			selector: (SEL)selector
			 context: (id)context
{
	ADD_READ(OFRunLoop_ReadQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_buffer = buffer;
		queueItem->_length = length;
	})
}

+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
		     exactLength: (size_t)exactLength
			  target: (id)target
			selector: (SEL)selector
			 context: (id)context
{
	ADD_READ(OFRunLoop_ExactReadQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_buffer = buffer;
		queueItem->_exactLength = exactLength;
	})
}

+ (void)of_addAsyncReadLineForStream: (OFStream *)stream
			    encoding: (of_string_encoding_t)encoding
			      target: (id)target
			    selector: (SEL)selector
			     context: (id)context
{
	ADD_READ(OFRunLoop_ReadLineQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_encoding = encoding;
	})
}

+ (void)of_addAsyncAcceptForTCPSocket: (OFTCPSocket *)stream
			       target: (id)target
			     selector: (SEL)selector
			      context: (id)context
{
	ADD_READ(OFRunLoop_AcceptQueueItem, stream, {
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
	})
}

+ (void)of_addAsyncReceiveForUDPSocket: (OFUDPSocket *)socket
				buffer: (void *)buffer
				length: (size_t)length
				target: (id)target
			      selector: (SEL)selector
			       context: (id)context
{
	ADD_READ(OFRunLoop_UDPReceiveQueueItem, socket, {
		queueItem->_buffer = buffer;
		queueItem->_length = length;
		queueItem->_target = [target retain];
		queueItem->_selector = selector;
		queueItem->_context = [context retain];
		queueItem->_buffer = buffer;
		queueItem->_length = length;
	})
}

# ifdef OF_HAVE_BLOCKS
+ (void)of_addAsyncReadForStream: (OFStream *)stream
			  buffer: (void *)buffer
			  length: (size_t)length

Modified src/OFStream.h from [fc84511d6f] to [39526e7198].

146
147
148
149
150
151
152
153
154
155



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

173
174
175
176
177


178
179
180
181
182
183
184


185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

203
204
205
206
207


208
209
210
211
212
213
214
146
147
148
149
150
151
152



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

172
173
174
175
176

177
178
179
180
181
182
183


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

203
204
205
206
207

208
209
210
211
212
213
214
215
216







-
-
-
+
+
+
















-
+




-
+
+





-
-
+
+

















-
+




-
+
+







#ifdef OF_HAVE_SOCKETS
/*!
 * @brief Asynchronously reads *at most* size bytes from the stream into a
 *	  buffer.
 *
 * On network streams, this might read less than the specified number of bytes.
 * If you want to read exactly the specified number of bytes, use
 * @ref asyncReadIntoBuffer:exactLength:block:. Note that a read can even
 * return 0 bytes - this does not necessarily mean that the stream ended, so
 * you still need to check @ref isAtEndOfStream.
 * @ref asyncReadIntoBuffer:exactLength:target:selector:context:. Note that a
 * read can even return 0 bytes - this does not necessarily mean that the
 * stream ended, so you still need to check @ref isAtEndOfStream.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 *
 * @param buffer The buffer into which the data is read.
 *		 The buffer must not be freed before the async read completed!
 * @param length The length of the data that should be read at most.
 *		 The buffer *must* be *at least* this big!
 * @param target The target on which the selector should be called when the
 *		 data has been received. If the method returns true, it will be
 *		 called again with the same buffer and maximum length when more
 *		 data has been received. If you want the next method in the
 *		 queue to handle the data received next, you need to return
 *		 false from the method.
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFStream *stream, void *buffer, size_t length,
 *		   OFException *exception)`.
 *		   id context, OFException *exception)`.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		     target: (id)target
		   selector: (SEL)selector;
		   selector: (SEL)selector
		    context: (nullable id)context;

/*!
 * @brief Asynchronously reads exactly the specified length bytes from the
 *	  stream into a buffer.
 *
 * Unlike @ref asyncReadIntoBuffer:length:target:selector:, this method does
 * not call the method when less than the specified length has been read -
 * Unlike @ref asyncReadIntoBuffer:length:target:selector:context:, this method
 * does not call the method when less than the specified length has been read -
 * instead, it waits until it got exactly the specified length, the stream has
 * ended or an exception occurred.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 *
 * @param buffer The buffer into which the data is read
 * @param length The length of the data that should be read.
 *		 The buffer *must* be *at least* this big!
 * @param target The target on which the selector should be called when the
 *		 data has been received. If the method returns true, it will be
 *		 called again with the same buffer and exact length when more
 *		 data has been received. If you want the next method in the
 *		 queue to handle the data received next, you need to return
 *		 false from the method.
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFStream *stream, void *buffer, size_t size,
 *		   OFException *exception)`.
 *		   id context, OFException *exception)`.
 */
- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		     target: (id)target
		   selector: (SEL)selector;
		   selector: (SEL)selector
		    context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously reads *at most* ref size bytes from the stream into a
 *	  buffer.
 *
 * On network streams, this might read less than the specified number of bytes.
617
618
619
620
621
622
623
624

625
626
627
628


629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645

646
647
648
649


650
651
652
653
654
655
656
619
620
621
622
623
624
625

626
627
628
629

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647

648
649
650
651

652
653
654
655
656
657
658
659
660







-
+



-
+
+
















-
+



-
+
+







 *
 * @param target The target on which to call the selector when the data has
 *		 been received. If the method returns true, it will be called
 *		 again when the next line has been received. If you want the
 *		 next method in the queue to handle the next line, you need to
 *		 return false from the method
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFStream *stream, OFString *line,
 *		   `bool (OFStream *stream, OFString *line, id context,
 *		   OFException *exception)`.
 */
- (void)asyncReadLineWithTarget: (id)target
		       selector: (SEL)selector;
		       selector: (SEL)selector
			context: (nullable id)context;

/*!
 * @brief Asynchronously reads with the specified encoding until a newline,
 *	  `\0`, end of stream or an exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a
 *	 valid file descriptor in order for this to work!
 *
 * @param encoding The encoding used by the stream
 * @param target The target on which to call the selector when the data has
 *		 been received. If the method returns true, it will be called
 *		 again when the next line has been received. If you want the
 *		 next method in the queue to handle the next line, you need to
 *		 return false from the method
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFStream *stream, OFString *line,
 *		   OFException *exception)`.
 *		   id context, OFException *exception)`.
 */
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			   target: (id)target
			 selector: (SEL)selector;
			 selector: (SEL)selector
			  context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously reads until a newline, `\0`, end of stream or an
 *	  exception occurs.
 *
 * @note The stream must implement @ref fileDescriptorForReading and return a

Modified src/OFStream.m from [e45f32eef4] to [3923d7b75a].

188
189
190
191
192
193
194

195
196
197
198
199
200


201
202
203
204
205
206

207
208
209
210
211
212


213
214
215
216
217
218
219
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
222
223







+





-
+
+






+





-
+
+







}

#ifdef OF_HAVE_SOCKETS
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		     target: (id)target
		   selector: (SEL)selector
		    context: (id)context
{
	[OFRunLoop of_addAsyncReadForStream: self
				     buffer: buffer
				     length: length
				     target: target
				   selector: selector];
				   selector: selector
				    context: context];
}

- (void)asyncReadIntoBuffer: (void *)buffer
		exactLength: (size_t)length
		     target: (id)target
		   selector: (SEL)selector
		    context: (id)context
{
	[OFRunLoop of_addAsyncReadForStream: self
				     buffer: buffer
				exactLength: length
				     target: target
				   selector: selector];
				   selector: selector
				    context: context];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadIntoBuffer: (void *)buffer
		     length: (size_t)length
		      block: (of_stream_async_read_block_t)block
{
808
809
810
811
812
813
814

815
816
817
818


819
820
821
822
823

824
825
826
827
828


829
830
831
832
833
834
835
812
813
814
815
816
817
818
819
820
821
822

823
824
825
826
827
828
829
830
831
832
833
834

835
836
837
838
839
840
841
842
843







+



-
+
+





+




-
+
+








	return line;
}

#ifdef OF_HAVE_SOCKETS
- (void)asyncReadLineWithTarget: (id)target
		       selector: (SEL)selector
			context: (id)context
{
	[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
				 target: target
			       selector: selector];
			       selector: selector
				context: context];
}

- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
			   target: (id)target
			 selector: (SEL)selector
			  context: (id)context
{
	[OFRunLoop of_addAsyncReadLineForStream: self
				       encoding: encoding
					 target: target
				       selector: selector];
				       selector: selector
					context: context];
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block
{
	[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
				  block: block];

Modified src/OFTCPSocket.h from [fe4d222a18] to [d70cc2f958].

123
124
125
126
127
128
129
130


131
132
133
134
135


136
137
138
139
140
141
142
123
124
125
126
127
128
129

130
131
132
133
134
135

136
137
138
139
140
141
142
143
144







-
+
+




-
+
+







 * @brief Asynchronously connect the OFTCPSocket to the specified destination.
 *
 * @param host The host to connect to
 * @param port The port on the host to connect to
 * @param target The target on which to call the selector once the connection
 *		 has been established
 * @param selector The selector to call on the target. The signature must be
 *		   `void (OFTCPSocket *socket, OFException *exception)`.
 *		   `void (OFTCPSocket *socket, id context,
 *		   OFException *exception)`.
 */
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
		    target: (id)target
		  selector: (SEL)selector;
		  selector: (SEL)selector
		   context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously connect the OFTCPSocket to the specified destination.
 *
 * @param host The host to connect to
 * @param port The port on the host to connect to
184
185
186
187
188
189
190
191

192
193
194


195
196
197
198
199
200
201
186
187
188
189
190
191
192

193
194
195

196
197
198
199
200
201
202
203
204







-
+


-
+
+







 *
 * @param target The target on which to execute the selector when a new
 *		 connection has been accepted. The method returns whether the
 *		 next incoming connection should be accepted by the specified
 *		 block as well.
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFTCPSocket *socket, OFTCPSocket *acceptedSocket,
 *		   OFException *exception)`.
 *		   id context, OFException *exception)`.
 */
- (void)asyncAcceptWithTarget: (id)target
		     selector: (SEL)selector;
		     selector: (SEL)selector
		      context: (nullable id)context;

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously accept an incoming connection.
 *
 * @param block The block to execute when a new connection has been accepted.
 *		Returns whether the next incoming connection should be accepted

Modified src/OFTCPSocket.m from [9870a76e72] to [e7861c7baa].

70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125







+











-
+
+
















+










+







{
	OFThread *_sourceThread;
	OFTCPSocket *_socket;
	OFString *_host;
	uint16_t _port;
	id _target;
	SEL _selector;
	id _context;
# ifdef OF_HAVE_BLOCKS
	of_tcp_socket_async_connect_block_t _block;
# endif
	OFException *_exception;
}

- initWithSourceThread: (OFThread *)sourceThread
		socket: (OFTCPSocket *)socket
		  host: (OFString *)host
		  port: (uint16_t)port
		target: (id)target
	      selector: (SEL)selector;
	      selector: (SEL)selector
	       context: (id)context;
# ifdef OF_HAVE_BLOCKS
- initWithSourceThread: (OFThread *)sourceThread
		socket: (OFTCPSocket *)socket
		  host: (OFString *)host
		  port: (uint16_t)port
		 block: (of_tcp_socket_async_connect_block_t)block;
# endif
@end

@implementation OFTCPSocket_ConnectThread
- initWithSourceThread: (OFThread *)sourceThread
		socket: (OFTCPSocket *)socket
		  host: (OFString *)host
		  port: (uint16_t)port
		target: (id)target
	      selector: (SEL)selector
	       context: (id)context
{
	self = [super init];

	@try {
		_sourceThread = [sourceThread retain];
		_socket = [socket retain];
		_host = [host copy];
		_port = port;
		_target = [target retain];
		_selector = selector;
		_context = [context retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172



173
174

175
176
177
178
179
180
181
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174



175
176
177
178

179
180
181
182
183
184
185
186







+

















-
-
-
+
+
+

-
+








- (void)dealloc
{
	[_sourceThread release];
	[_socket release];
	[_host release];
	[_target release];
	[_context release];
# ifdef OF_HAVE_BLOCKS
	[_block release];
# endif
	[_exception release];

	[super dealloc];
}

- (void)didConnect
{
	[self join];

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		_block(_socket, _exception);
	else {
# endif
		void (*func)(id, SEL, OFTCPSocket *, OFException *) =
		    (void (*)(id, SEL, OFTCPSocket *, OFException *))[_target
		    methodForSelector: _selector];
		void (*func)(id, SEL, OFTCPSocket *, id, OFException *) =
		    (void (*)(id, SEL, OFTCPSocket *, id, OFException *))
		    [_target methodForSelector: _selector];

		func(_target, _selector, _socket, _exception);
		func(_target, _selector, _socket, _context, _exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

- (id)main
{
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326
327
328


329
330
331
332
333
334
335
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
341
342







+









-
+
+







}

#ifdef OF_HAVE_THREADS
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
		    target: (id)target
		  selector: (SEL)selector
		   context: (id)context
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFTCPSocket_ConnectThread alloc]
	    initWithSourceThread: [OFThread currentThread]
			  socket: self
			    host: host
			    port: port
			  target: target
			selector: selector] autorelease] start];
			selector: selector
			 context: context] autorelease] start];

	objc_autoreleasePoolPop(pool);
}

# ifdef OF_HAVE_BLOCKS
- (void)asyncConnectToHost: (OFString *)host
		      port: (uint16_t)port
570
571
572
573
574
575
576

577
578
579
580


581
582
583
584
585
586
587
577
578
579
580
581
582
583
584
585
586
587

588
589
590
591
592
593
594
595
596







+



-
+
+







	}

	return client;
}

- (void)asyncAcceptWithTarget: (id)target
		     selector: (SEL)selector
		      context: (id)context
{
	[OFRunLoop of_addAsyncAcceptForTCPSocket: self
					  target: target
					selector: selector];
					selector: selector
					 context: context];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncAcceptWithBlock: (of_tcp_socket_async_accept_block_t)block
{
	[OFRunLoop of_addAsyncAcceptForTCPSocket: self
					   block: block];

Modified src/OFUDPSocket.h from [05fb60ba2c] to [dea0dfc05e].

123
124
125
126
127
128
129
130


131
132
133
134
135


136
137
138
139
140
141
142
123
124
125
126
127
128
129

130
131
132
133
134
135

136
137
138
139
140
141
142
143
144







-
+
+




-
+
+







 *
 * @param host The host to resolve
 * @param port The port for the resulting address
 * @param target The target on which to call the selector once the host has been
 *		 resolved
 * @param selector The selector to call on the target. The signature must be
 *		   `void (OFString *host, uint16_t port,
 *		   of_udp_socket_address_t address, OFException *exception)`.
 *		   of_udp_socket_address_t address, id context,
 *		   OFException *exception)`.
 */
+ (void)asyncResolveAddressForHost: (OFString *)host
			      port: (uint16_t)port
			    target: (id)target
			  selector: (SEL)selector;
			  selector: (SEL)selector
			   context: (nullable id)context;

# ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously resolves the specified host and creates an address for
 *	  the host / port pair.
 *
 * @param host The host to resolve
201
202
203
204
205
206
207
208


209
210
211
212
213


214
215
216
217
218
219
220
203
204
205
206
207
208
209

210
211
212
213
214
215

216
217
218
219
220
221
222
223
224







-
+
+




-
+
+







 *		 datagram has been received. If the method returns true, it
 *		 will be called again with the same buffer and maximum length
 *		 when more datagrams have been received. If you want the next
 *		 method in the queue to handle the datagram received next, you
 *		 need to return false from the method.
 * @param selector The selector to call on the target. The signature must be
 *		   `bool (OFUDPSocket *socket, void *buffer, size_t length,
 *		   of_udp_socket_address_t, OFException *exception)`.
 *		   of_udp_socket_address_t, id context,
 *		   OFException *exception)`.
 */
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
			target: (id)target
		      selector: (SEL)selector;
		      selector: (SEL)selector
		       context: (nullable id)context;

#ifdef OF_HAVE_BLOCKS
/*!
 * @brief Asynchronously receives a datagram and stores it into the specified
 *	  buffer.
 *
 * If the buffer is too small, the datagram is truncated.

Modified src/OFUDPSocket.m from [c8e3c83553] to [c1cf4f8ea1].

47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99







+











-
+
+














+









+







@interface OFUDPSocket_ResolveThread: OFThread
{
	OFThread *_sourceThread;
	OFString *_host;
	uint16_t _port;
	id _target;
	SEL _selector;
	id _context;
# ifdef OF_HAVE_BLOCKS
	of_udp_socket_async_resolve_block_t _block;
# endif
	of_udp_socket_address_t _address;
	OFException *_exception;
}

- initWithSourceThread: (OFThread *)sourceThread
		  host: (OFString *)host
		  port: (uint16_t)port
		target: (id)target
	      selector: (SEL)selector;
	      selector: (SEL)selector
	       context: (id)context;
# ifdef OF_HAVE_BLOCKS
- initWithSourceThread: (OFThread *)sourceThread
		  host: (OFString *)host
		  port: (uint16_t)port
		 block: (of_udp_socket_async_resolve_block_t)block;
# endif
@end

@implementation OFUDPSocket_ResolveThread
- initWithSourceThread: (OFThread *)sourceThread
		  host: (OFString *)host
		  port: (uint16_t)port
		target: (id)target
	      selector: (SEL)selector
	       context: (id)context
{
	self = [super init];

	@try {
		_sourceThread = [sourceThread retain];
		_host = [host retain];
		_port = port;
		_target = [target retain];
		_selector = selector;
		_context = [context retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145


146
147


148
149
150
151
152
153
154
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

147
148


149
150
151

152
153
154
155
156
157
158
159
160







+


















-
+

-
-
+
+

-
+
+







# endif

- (void)dealloc
{
	[_sourceThread release];
	[_host release];
	[_target release];
	[_context release];
# ifdef OF_HAVE_BLOCKS
	[_block release];
# endif
	[_exception release];

	[super dealloc];
}

- (void)didResolve
{
	[self join];

# ifdef OF_HAVE_BLOCKS
	if (_block != NULL)
		_block(_host, _port, _address, _exception);
	else {
# endif
		void (*func)(id, SEL, OFString *, uint16_t,
		    of_udp_socket_address_t, OFException *) =
		    of_udp_socket_address_t, id, OFException *) =
		    (void (*)(id, SEL, OFString *, uint16_t,
		    of_udp_socket_address_t, OFException *))[_target
		    methodForSelector: _selector];
		    of_udp_socket_address_t, id, OFException *))
		    [_target methodForSelector: _selector];

		func(_target, _selector, _host, _port, _address, _exception);
		func(_target, _selector, _host, _port, _address, _context,
		    _exception);
# ifdef OF_HAVE_BLOCKS
	}
# endif
}

- (id)main
{
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333
334


335
336
337
338
339
340
341
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







+








-
+
+







}

#ifdef OF_HAVE_THREADS
+ (void)asyncResolveAddressForHost: (OFString *)host
			      port: (uint16_t)port
			    target: (id)target
			  selector: (SEL)selector
			   context: (id)context
{
	void *pool = objc_autoreleasePoolPush();

	[[[[OFUDPSocket_ResolveThread alloc]
	    initWithSourceThread: [OFThread currentThread]
			    host: host
			    port: port
			  target: target
			selector: selector] autorelease] start];
			selector: selector
			 context: context] autorelease] start];

	objc_autoreleasePoolPop(pool);
}

# ifdef OF_HAVE_BLOCKS
+ (void)asyncResolveAddressForHost: (OFString *)host
			      port: (uint16_t)port
556
557
558
559
560
561
562

563
564
565
566
567
568


569
570
571
572
573
574
575
564
565
566
567
568
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
584
585







+





-
+
+







	return ret;
}

- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
			target: (id)target
		      selector: (SEL)selector
		       context: (id)context
{
	[OFRunLoop of_addAsyncReceiveForUDPSocket: self
					   buffer: buffer
					   length: length
					   target: target
					 selector: selector];
					 selector: selector
					  context: context];
}

#ifdef OF_HAVE_BLOCKS
- (void)asyncReceiveIntoBuffer: (void *)buffer
			length: (size_t)length
			 block: (of_udp_socket_async_receive_block_t)block
{

Modified utils/ofhttp/OFHTTP.m from [2ea2fa69f0] to [fb3cc5ba3d].

776
777
778
779
780
781
782
783


784
785
786
787
788
789
790
791
792
793
794
795
796
797

798
799
800
801
802
803
804
776
777
778
779
780
781
782

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806







-
+
+














+







	[_currentFileName release];
	_currentFileName = nil;

	[response asyncReadIntoBuffer: _buffer
			       length: [OFSystemInfo pageSize]
			       target: self
			     selector: @selector(stream:didReadIntoBuffer:
					   length:exception:)];
					   length:context:exception:)
			      context: nil];

	return;

next:
	[_currentFileName release];
	_currentFileName = nil;

	[self performSelector: @selector(downloadNextURL)
		   afterDelay: 0];
}

-      (bool)stream: (OFHTTPResponse *)response
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	    context: (id)context
	  exception: (OFException *)e
{
	if (e != nil) {
		OFString *URL;

		[_progressBar stop];
		[_progressBar draw];