︙ | | |
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
-
+
+
|
#import "OFTruncatedDataException.h"
#import "OFUnsupportedProtocolException.h"
#import "OFUnsupportedVersionException.h"
#import "OFWriteFailedException.h"
#define REDIRECTS_DEFAULT 10
@interface OFHTTPClientRequestHandler: OFObject
@interface OFHTTPClientRequestHandler: OFObject <OFStreamDelegate>
{
@public
OFHTTPClient *_client;
OFHTTPRequest *_request;
OFString *_requestString;
unsigned int _redirects;
id _context;
bool _firstLine;
OFString *_version;
int _status;
OFMutableDictionary OF_GENERIC(OFString *, OFString *) *_serverHeaders;
}
|
︙ | | |
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
+
|
return self;
}
- (void)dealloc
{
[_client release];
[_request release];
[_requestString release];
[_context release];
[_version release];
[_serverHeaders release];
[super dealloc];
}
|
︙ | | |
474
475
476
477
478
479
480
481
482
483
484
485
486
487
|
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
|
+
+
|
if ([_client->_delegate respondsToSelector: @selector(client:
didReceiveHeaders:statusCode:request:context:)])
[_client->_delegate client: _client
didReceiveHeaders: _serverHeaders
statusCode: _status
request: _request
context: _context];
[sock setDelegate: nil];
[self performSelector: @selector(createResponseWithSocket:)
withObject: sock
afterDelay: 0];
return false;
}
|
︙ | | |
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
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
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
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
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
|
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
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
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
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
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
|
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
-
+
-
-
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
+
+
+
-
|
[_serverHeaders setObject: value
forKey: key];
return true;
}
- (bool)socket: (OFTCPSocket *)sock
- (bool)stream: (OF_KINDOF(OFStream *))sock
didReadLine: (OFString *)line
context: (id)context
exception: (id)exception
{
bool ret;
if (exception != nil) {
if ([exception isKindOfClass:
[OFInvalidEncodingException class]])
exception = [OFInvalidServerReplyException exception];
[self raiseException: exception];
return false;
}
@try {
if (_firstLine) {
_firstLine = false;
ret = [self handleFirstLine: line];
} else
ret = [self handleServerHeader: line
socket: sock];
} @catch (id e) {
[self raiseException: e];
ret = false;
}
return ret;
}
- (size_t)socket: (OFTCPSocket *)sock
- (void)stream: (OF_KINDOF(OFStream *))sock
didWriteRequest: (const void **)request
length: (size_t)length
context: (id)context
exception: (id)exception
didFailWithException: (id)exception
{
if (exception != nil) {
if ([exception isKindOfClass: [OFWriteFailedException class]] &&
([exception errNo] == ECONNRESET ||
if ([exception isKindOfClass: [OFWriteFailedException class]] &&
([exception errNo] == ECONNRESET || [exception errNo] == EPIPE)) {
[exception errNo] == EPIPE)) {
/* In case a keep-alive connection timed out */
[self closeAndReconnect];
return 0;
}
/* In case a keep-alive connection timed out */
[self closeAndReconnect];
return;
}
if ([exception isKindOfClass: [OFInvalidEncodingException class]])
exception = [OFInvalidServerReplyException exception];
[self raiseException: exception];
[self raiseException: exception];
return 0;
}
}
- (size_t)stream: (OF_KINDOF(OFStream *))sock
didWriteBuffer: (const void **)request
length: (size_t)length
{
_firstLine = true;
[_requestString release];
_requestString = nil;
if ([[_request headers] objectForKey: @"Content-Length"] != nil) {
[sock setDelegate: nil];
OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc]
initWithHandler: self
socket: sock] autorelease];
if ([_client->_delegate respondsToSelector:
@selector(client:wantsRequestBody:request:context:)])
[_client->_delegate client: _client
wantsRequestBody: requestBody
request: _request
context: _context];
} else
[sock asyncReadLineWithTarget: self
[sock asyncReadLine];
selector: @selector(socket:didReadLine:
context:exception:)
context: nil];
return 0;
}
- (void)handleSocket: (OFTCPSocket *)sock
{
/*
* As a work around for a bug with split packets in lighttpd when using
* HTTPS, we construct the complete request in a buffer string and then
* send it all at once.
*
* We do not use the socket's write buffer in case we need to resend
* the entire request (e.g. in case a keep-alive connection timed out).
*/
@try {
[_requestString release];
OFString *requestString = constructRequestString(_request);
_requestString = [constructRequestString(_request) retain];
/*
* Pass requestString as context to retain it so that the
* underlying buffer lives long enough.
*/
[sock asyncWriteBuffer: [requestString UTF8String]
length: [requestString UTF8StringLength]
[sock asyncWriteBuffer: [_requestString UTF8String]
length: [_requestString UTF8StringLength]];
target: self
selector: @selector(socket:didWriteRequest:
length:context:exception:)
context: requestString];
} @catch (id e) {
[self raiseException: e];
return;
}
}
- (void)socketDidConnect: (OFTCPSocket *)sock
context: (id)context
exception: (id)exception
{
if (exception != nil) {
[self raiseException: exception];
return;
}
[sock setDelegate: self];
if ([_client->_delegate respondsToSelector:
@selector(client:didCreateSocket:request:context:)])
[_client->_delegate client: _client
didCreateSocket: sock
request: _request
context: _context];
[self performSelector: @selector(handleSocket:)
withObject: sock
afterDelay: 0];
}
- (bool)throwAwayContent: (OFHTTPClientResponse *)response
buffer: (char *)buffer
length: (size_t)length
context: (OFTCPSocket *)sock
exception: (id)exception
{
if (exception != nil) {
[self raiseException: exception];
return false;
}
if ([response isAtEndOfStream]) {
[self freeMemory: buffer];
[_client->_lastResponse release];
_client->_lastResponse = nil;
[self performSelector: @selector(handleSocket:)
withObject: sock
afterDelay: 0];
return false;
}
return true;
}
- (void)start
{
OFURL *URL = [_request URL];
OFTCPSocket *sock;
/* Can we reuse the last socket? */
if (_client->_socket != nil && ![_client->_socket isAtEndOfStream] &&
[[_client->_lastURL scheme] isEqual: [URL scheme]] &&
[[_client->_lastURL host] isEqual: [URL host]] &&
[_client->_lastURL port] == [URL port]) {
[_client->_lastURL port] == [URL port] &&
(_client->_lastWasHEAD ||
[_client->_lastResponse isAtEndOfStream])) {
/*
* Set _socket to nil, so that in case of an error it won't be
* reused. If everything is successful, we set _socket again
* at the end.
*/
sock = [_client->_socket autorelease];
_client->_socket = nil;
[_client->_lastURL release];
_client->_lastURL = nil;
if (!_client->_lastWasHEAD &&
![_client->_lastResponse isAtEndOfStream]) {
/* Throw away content that has not been read yet */
char *buffer = [self allocMemoryWithSize: 512];
[_client->_lastResponse
asyncReadIntoBuffer: buffer
length: 512
target: self
selector: @selector(throwAwayContent:
buffer:length:context:
exception:)
context: sock];
} else {
[_client->_lastResponse release];
_client->_lastResponse = nil;
[_client->_lastResponse release];
_client->_lastResponse = nil;
[self performSelector: @selector(handleSocket:)
withObject: sock
afterDelay: 0];
[self performSelector: @selector(handleSocket:)
withObject: sock
afterDelay: 0];
}
} else
[self closeAndReconnect];
}
- (void)closeAndReconnect
{
@try {
|
︙ | | |
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
|
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
|
+
-
+
-
-
-
|
{
if (_socket == nil)
return;
if (_toWrite > 0)
@throw [OFTruncatedDataException exception];
[_socket setDelegate: _handler];
[_socket asyncReadLineWithTarget: _handler
[_socket asyncReadLine];
selector: @selector(socket:didReadLine:context:
exception:)
context: nil];
[_socket release];
_socket = nil;
}
- (int)fileDescriptorForWriting
{
|
︙ | | |
︙ | | |
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
|
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
|
-
-
+
+
-
+
|
/*
* FIXME: Key normalization replaces headers like "DNT" with "Dnt".
* FIXME: Errors are not reported to the user.
*/
@interface OFHTTPServer ()
- (bool)of_socket: (OF_KINDOF(OFTCPSocket *))sock
didAcceptSocket: (OF_KINDOF(OFTCPSocket *))clientSocket
- (bool)of_socket: (OFTCPSocket *)sock
didAcceptSocket: (OFTCPSocket *)clientSocket
context: (id)context
exception: (id)exception;
@end
@interface OFHTTPServerResponse: OFHTTPResponse <OFReadyForWritingObserving>
{
OF_KINDOF(OFTCPSocket *) _socket;
OFHTTPServer *_server;
OFHTTPRequest *_request;
bool _chunked, _headersSent;
}
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
server: (OFHTTPServer *)server
request: (OFHTTPRequest *)request;
@end
@interface OFHTTPServer_Connection: OFObject
@interface OFHTTPServer_Connection: OFObject <OFStreamDelegate>
{
@public
OF_KINDOF(OFTCPSocket *) _socket;
OFHTTPServer *_server;
OFTimer *_timer;
enum {
AWAITING_PROLOG,
|
︙ | | |
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
-
-
-
-
|
OFMutableDictionary *_headers;
size_t _contentLength;
OFStream *_requestBody;
}
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
server: (OFHTTPServer *)server;
- (bool)socket: (OF_KINDOF(OFTCPSocket *))sock
didReadLine: (OFString *)line
context: (id)context
exception: (id)exception;
- (bool)parseProlog: (OFString *)line;
- (bool)parseHeaders: (OFString *)line;
- (bool)sendErrorAndClose: (short)statusCode;
- (void)createResponse;
@end
@interface OFHTTPServerRequestBodyStream: OFStream <OFReadyForReadingObserving>
|
︙ | | |
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
|
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
|
-
+
-
-
-
+
|
[_path release];
[_headers release];
[_requestBody release];
[super dealloc];
}
- (bool)socket: (OF_KINDOF(OFTCPSocket *))sock
- (bool)stream: (OF_KINDOF(OFStream *))sock
didReadLine: (OFString *)line
context: (id)context
exception: (id)exception
{
if (line == nil || exception != nil)
if (line == nil)
return false;
@try {
switch (_state) {
case AWAITING_PROLOG:
return [self parseProlog: line];
case PARSING_HEADERS:
|
︙ | | |
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
|
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
|
-
-
+
+
+
-
+
-
-
-
|
- (void)stop
{
[_listeningSocket cancelAsyncRequests];
[_listeningSocket release];
_listeningSocket = nil;
}
- (bool)of_socket: (OF_KINDOF(OFTCPSocket *))sock
didAcceptSocket: (OF_KINDOF(OFTCPSocket *))clientSocket
- (bool)of_socket: (OFTCPSocket *)sock
didAcceptSocket: (OFTCPSocket *)clientSocket
context: (id)context
exception: (id)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 setDelegate: connection];
[clientSocket asyncReadLineWithTarget: connection
[clientSocket asyncReadLine];
selector: @selector(socket:didReadLine:
context:exception:)
context: nil];
return true;
}
@end
|
︙ | | |
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
+
+
|
}
@end
#ifdef OF_HAVE_SOCKETS
@interface OFRunLoop_QueueItem: OFObject
{
@public
id _delegate;
/* TODO: Remove once everything is moved to using delegates */
id _target;
SEL _selector;
id _context;
}
- (bool)handleObject: (id)object;
@end
|
︙ | | |
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
+
|
- (bool)handleObject: (id)object
{
OF_UNRECOGNIZED_SELECTOR
}
- (void)dealloc
{
[_delegate release];
[_target release];
[_context release];
[super dealloc];
}
@end
|
︙ | | |
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
350
351
352
353
354
|
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
+
|
}
# ifdef OF_HAVE_BLOCKS
if (_block != NULL)
return _block(object, _buffer, length, exception);
else {
# endif
if (exception == nil) {
if (![_delegate respondsToSelector:
@selector(stream:didReadIntoBuffer:length:)])
return false;
bool (*func)(id, SEL, OFStream *, void *, size_t, id, id) =
(bool (*)(id, SEL, OFStream *, void *, size_t, id, id))
[_target methodForSelector: _selector];
return [_delegate stream: object
didReadIntoBuffer: _buffer
length: length];
} else {
if ([_delegate respondsToSelector:
@selector(stream:didFailWithException:)])
[_delegate stream: object
didFailWithException: exception];
return func(_target, _selector, object, _buffer, length,
return false;
_context, exception);
}
# ifdef OF_HAVE_BLOCKS
}
# endif
}
# ifdef OF_HAVE_BLOCKS
- (void)dealloc
|
︙ | | |
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
|
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
|
-
+
-
-
+
+
+
+
+
-
+
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
|
if (!_block(object, _buffer, _readLength, exception))
return false;
_readLength = 0;
return true;
} else {
# endif
bool (*func)(id, SEL, OFStream *, void *, size_t, id, id) =
if (exception == nil) {
(bool (*)(id, SEL, OFStream *, void *, size_t, id, id))
[_target methodForSelector: _selector];
if (![_delegate respondsToSelector:
@selector(stream:didReadIntoBuffer:length:)])
return false;
if (![_delegate stream: object
didReadIntoBuffer: _buffer
if (!func(_target, _selector, object, _buffer, _readLength,
length: _readLength])
_context, exception))
return false;
return false;
_readLength = 0;
return true;
_readLength = 0;
return true;
} else {
if ([_delegate respondsToSelector:
@selector(stream:didFailWithException:)])
[_delegate stream: object
didFailWithException: exception];
return false;
}
# ifdef OF_HAVE_BLOCKS
}
# endif
}
# ifdef OF_HAVE_BLOCKS
- (void)dealloc
|
︙ | | |
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
|
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
|
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
-
+
-
+
|
return true;
# ifdef OF_HAVE_BLOCKS
if (_block != NULL)
return _block(object, line, exception);
else {
# endif
if (exception == nil) {
if (![_delegate respondsToSelector:
@selector(stream:didReadLine:)])
return false;
bool (*func)(id, SEL, OFStream *, OFString *, id, id) =
(bool (*)(id, SEL, OFStream *, OFString *, id, id))
[_target methodForSelector: _selector];
return [_delegate stream: object
didReadLine: line];
} else {
if ([_delegate respondsToSelector:
@selector(stream:didFailWithException:)])
[_delegate stream: object
didFailWithException: exception];
return func(_target, _selector, object, line, _context,
return false;
exception);
}
# ifdef OF_HAVE_BLOCKS
}
# endif
}
# ifdef OF_HAVE_BLOCKS
- (void)dealloc
|
︙ | | |
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
|
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
|
-
-
-
+
+
+
+
-
-
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
|
if (_length == 0)
return false;
_writtenLength = 0;
return true;
} else {
# endif
bool (*func)(id, SEL, OFStream *, const void *, size_t, id,
id) = (bool (*)(id, SEL, OFStream *, const void *, size_t,
id, id))[_target methodForSelector: _selector];
if (exception == nil) {
if (![_delegate respondsToSelector:
@selector(stream:didWriteBuffer:length:)])
return false;
_length = func(_target, _selector, object, &_buffer,
_writtenLength, _context, exception);
_length = [_delegate stream: object
didWriteBuffer: &_buffer
length: _length];
if (_length == 0)
return false;
if (_length == 0)
return false;
_writtenLength = 0;
return true;
_writtenLength = 0;
return true;
} else {
if ([_delegate respondsToSelector:
@selector(stream:didFailWithException:)])
[_delegate stream: object
didFailWithException: exception];
return false;
}
# ifdef OF_HAVE_BLOCKS
}
# endif
}
# ifdef OF_HAVE_BLOCKS
- (void)dealloc
|
︙ | | |
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
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
|
766
767
768
769
770
771
772
773
774
775
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
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
|
-
+
-
-
-
-
+
-
-
+
-
-
-
-
+
-
-
+
-
-
-
-
+
-
-
+
-
-
-
-
+
-
|
objc_autoreleasePoolPop(pool);
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
stream
buffer: (void *)buffer
length: (size_t)length
mode: (of_run_loop_mode_t)mode
target: (id)target
delegate: (id <OFStreamDelegate>)delegate
selector: (SEL)selector
context: (id)context
{
ADD_READ(OFRunLoop_ReadQueueItem, stream, mode, {
queueItem->_target = [target retain];
queueItem->_selector = selector;
queueItem->_delegate = [delegate retain];
queueItem->_context = [context retain];
queueItem->_buffer = buffer;
queueItem->_length = length;
})
}
+ (void)of_addAsyncReadForStream: (OFStream <OFReadyForReadingObserving> *)
stream
buffer: (void *)buffer
exactLength: (size_t)exactLength
mode: (of_run_loop_mode_t)mode
target: (id)target
delegate: (id <OFStreamDelegate>)delegate
selector: (SEL)selector
context: (id)context
{
ADD_READ(OFRunLoop_ExactReadQueueItem, stream, mode, {
queueItem->_target = [target retain];
queueItem->_selector = selector;
queueItem->_delegate = [delegate retain];
queueItem->_context = [context retain];
queueItem->_buffer = buffer;
queueItem->_exactLength = exactLength;
})
}
+ (void)of_addAsyncReadLineForStream: (OFStream <OFReadyForReadingObserving> *)
stream
encoding: (of_string_encoding_t)encoding
mode: (of_run_loop_mode_t)mode
target: (id)target
delegate: (id <OFStreamDelegate>)delegate
selector: (SEL)selector
context: (id)context
{
ADD_READ(OFRunLoop_ReadLineQueueItem, stream, mode, {
queueItem->_target = [target retain];
queueItem->_selector = selector;
queueItem->_delegate = [delegate retain];
queueItem->_context = [context retain];
queueItem->_encoding = encoding;
})
}
+ (void)of_addAsyncWriteForStream: (OFStream <OFReadyForWritingObserving> *)
stream
buffer: (const void *)buffer
length: (size_t)length
mode: (of_run_loop_mode_t)mode
target: (id)target
delegate: (id <OFStreamDelegate>)delegate
selector: (SEL)selector
context: (id)context
{
ADD_WRITE(OFRunLoop_WriteQueueItem, stream, mode, {
queueItem->_target = [target retain];
queueItem->_selector = selector;
queueItem->_delegate = [delegate retain];
queueItem->_context = [context retain];
queueItem->_buffer = buffer;
queueItem->_length = length;
})
}
+ (void)of_addAsyncConnectForTCPSocket: (OFTCPSocket *)stream
mode: (of_run_loop_mode_t)mode
|
︙ | | |
︙ | | |
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
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
|
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
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
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
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
|
-
+
+
-
+
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
/*! @file */
@class OFStream;
@class OFData;
#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_BLOCKS)
/*!
* @brief A block which is called when data was read from the stream.
* @brief A block which is called when data was read asynchronously from a
* stream.
*
* @param stream The stream on which data was read
* @param buffer A buffer with the data that has been read
* @param length The length of the data that has been read
* @param exception An exception which occurred while reading or `nil` on
* success
* @return A bool whether the same block should be used for the next read
*/
typedef bool (^of_stream_async_read_block_t)(OF_KINDOF(OFStream *) stream,
void *buffer, size_t length, id _Nullable exception);
/*!
* @brief A block which is called when a line was read from the stream.
* @brief A block which is called when a line was read asynchronously from a
* stream.
*
* @param stream The stream on which a line was read
* @param line The line which has been read or `nil` when the end of stream
* occurred
* @param exception An exception which occurred while reading or `nil` on
* success
* @return A bool whether the same block should be used for the next read
*/
typedef bool (^of_stream_async_read_line_block_t)(OF_KINDOF(OFStream *) stream,
OFString *_Nullable line, id _Nullable exception);
/*!
* @brief A block which is called when data was written to the stream.
* @brief A block which is called when data was written asynchronously to a
* stream.
*
* @param stream The stream to which data was written
* @param buffer A pointer to the buffer which was written to the stream. This
* can be changed to point to a different buffer to be used on the
* next write.
* @param bytesWritten The number of bytes which have been written. This
* matches the length specified on the asynchronous write
* if no exception was encountered.
* @param exception An exception which occurred while writing or `nil` on
* success
* @return The length to repeat the write with or 0 if it should not repeat.
* The buffer may be changed, so that every time a new buffer and length
* can be specified while the callback stays the same.
* can be specified
*/
typedef size_t (^of_stream_async_write_block_t)(OF_KINDOF(OFStream *) stream,
const void *_Nonnull *_Nonnull buffer, size_t bytesWritten,
id _Nullable exception);
#endif
/*!
* @protocol OFStreamDelegate OFStream.h ObjFW/OFStream.h
*
* A delegate for OFStream.
*/
@protocol OFStreamDelegate <OFObject>
@optional
/*!
* @brief This method is called when data was read asynchronously from the
* stream.
*
* @param stream The stream on which data was read
* @param buffer A buffer with the data that has been read
* @param length The length of the data that has been read
* @return A bool whether the read should be repeated
*/
- (bool)stream: (OF_KINDOF(OFStream *))stream
didReadIntoBuffer: (void *)buffer
length: (size_t)length;
/*!
* @brief This method is called when a line was read asynchronously from the
* stream.
*
* @param stream The stream on which a line was read
* @param line The line which has been read or `nil` when the end of stream
* occurred
* @return A bool whether the read should be repeated
*/
- (bool)stream: (OF_KINDOF(OFStream *))stream
didReadLine: (nullable OFString *)line;
/*!
* @brief This method is called when data was written asynchronously to the
* stream.
*
* @param stream The stream to which data was written
* @param buffer A pointer to the buffer which was written to the stream. This
* can be changed to point to a different buffer to be used on the
* next write.
* @param length The length of the buffer that has been written
* @return The length to repeat the write with or 0 if it should not repeat.
* The buffer may be changed, so that every time a new buffer and
* length can be specified
*/
- (size_t)stream: (OF_KINDOF(OFStream *))stream
didWriteBuffer: (const void *_Nonnull *_Nonnull)buffer
length: (size_t)length;
/*!
* @brief This method is called when an exception occurred during an
* asynchronous operation on the stream.
*
* @param stream The stream for which an exception occurred
* @param exception The exception which occurred for the stream
*/
- (void)stream: (OF_KINDOF(OFStream *))stream
didFailWithException: (id)exception;
@end
/*!
* @class OFStream OFStream.h ObjFW/OFStream.h
*
* @brief A base class for different types of streams.
*
* @warning Even though the OFCopying protocol is implemented, it does *not*
* return an independent copy of the stream, but instead retains it.
|
︙ | | |
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
+
|
#endif
char *_Nullable _readBuffer, *_Nullable _readBufferMemory;
char *_Nullable _writeBuffer;
size_t _readBufferLength, _writeBufferLength;
bool _writeBuffered, _waitingForDelimiter;
@protected
bool _blocking;
id <OFStreamDelegate> _Nullable _delegate;
}
/*!
* @brief Whether the end of the stream has been reached.
*/
@property (readonly, nonatomic, getter=isAtEndOfStream) bool atEndOfStream;
|
︙ | | |
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
+
+
+
+
+
+
+
+
+
|
* @brief Whether the stream is in blocking mode.
*
* By default, a stream is in blocking mode.
* On Win32, setting this currently only works for sockets!
*/
@property (nonatomic, getter=isBlocking) bool blocking;
/*!
* @brief The delegate for asynchronous operations on the stream.
*
* @note The delegate is retained for as long as asynchronous operations are
* still outstanding.
*/
@property OF_NULLABLE_PROPERTY (assign, nonatomic)
id <OFStreamDelegate> delegate;
/*!
* @brief 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 readIntoBuffer:exactLength:. Note that a read can even return 0 bytes -
* this does not necessarily mean that the stream ended, so you still need to
|
︙ | | |
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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
343
|
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
|
* @note The stream must conform to @ref OFReadyForReadingObserving 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,
* id context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadIntoBuffer: (void *)buffer
length: (size_t)length
length: (size_t)length;
target: (id)target
selector: (SEL)selector
context: (nullable id)context;
/*!
* @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: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 atEndOfStream.
*
* @note The stream must conform to @ref OFReadyForReadingObserving 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 runLoopMode The run loop mode in which to perform the async read
* @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,
* id context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadIntoBuffer: (void *)buffer
length: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
runLoopMode: (of_run_loop_mode_t)runLoopMode;
target: (id)target
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: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 conform to @ref OFReadyForReadingObserving 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 length,
* id context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadIntoBuffer: (void *)buffer
exactLength: (size_t)length
exactLength: (size_t)length;
target: (id)target
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: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 conform to @ref OFReadyForReadingObserving 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 runLoopMode The run loop mode in which to perform the async read
* @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 length,
* id context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadIntoBuffer: (void *)buffer
exactLength: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
runLoopMode: (of_run_loop_mode_t)runLoopMode;
target: (id)target
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.
|
︙ | | |
774
775
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
807
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
836
837
838
839
840
841
842
843
844
845
846
847
848
849
|
795
796
797
798
799
800
801
802
803
804
805
806
807
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
|
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
|
#ifdef OF_HAVE_SOCKETS
/*!
* @brief Asynchronously reads until a newline, `\0`, end of stream or an
* exception occurs.
*
* @note The stream must conform to @ref OFReadyForReadingObserving in order
* for this to work!
*
* @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, id context,
* id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadLineWithTarget: (id)target
- (void)asyncReadLine;
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 conform to @ref OFReadyForReadingObserving 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, id context,
* id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding;
target: (id)target
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 conform to @ref OFReadyForReadingObserving in order
* for this to work!
*
* @param encoding The encoding used by the stream
* @param runLoopMode The run loop mode in which to perform the async read
* @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, id context,
* id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
runLoopMode: (of_run_loop_mode_t)runLoopMode
runLoopMode: (of_run_loop_mode_t)runLoopMode;
target: (id)target
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 conform to @ref OFReadyForReadingObserving in order
|
︙ | | |
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
|
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
|
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
|
*
* @note The stream must conform to @ref OFReadyForWritingObserving in order
* for this to work!
*
* @param buffer The buffer from which the data is written into the stream. The
* buffer needs to be valid until the write request is completed!
* @param length The length of the data that should be written
* @param target The target on which the selector should be called when the
* data has been written. The method should return the length for
* the next write with the same callback or 0 if it should not
* repeat. The buffer may be changed, so that every time a new
* buffer and length can be specified while the callback stays
* the same.
* @param selector The selector to call on the target. It should return the
* length for the next write with the same callback or 0 if it
* should not repeat. The signature must be `size_t (OFStream
* *stream, const void *buffer, size_t bytesWritten, id
* context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncWriteBuffer: (const void *)buffer
length: (size_t)length
length: (size_t)length;
target: (id)target
selector: (SEL)selector
context: (nullable id)context;
/*!
* @brief Asynchronously writes a buffer into the stream.
*
* @note The stream must conform to @ref OFReadyForWritingObserving in order
* for this to work!
*
* @param buffer The buffer from which the data is written into the stream. The
* buffer needs to be valid until the write request is completed!
* @param length The length of the data that should be written
* @param runLoopMode The run loop mode in which to perform the async write
* @param target The target on which the selector should be called when the
* data has been written. The method should return the length for
* the next write with the same callback or 0 if it should not
* repeat. The buffer may be changed, so that every time a new
* buffer and length can be specified while the callback stays
* the same.
* @param selector The selector to call on the target. It should return the
* length for the next write with the same callback or 0 if it
* should not repeat. The signature must be `size_t (OFStream
* *stream, const void *buffer, size_t bytesWritten, id
* context, id exception)`.
* @param context A context object to pass along to the target
*/
- (void)asyncWriteBuffer: (const void *)buffer
length: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
runLoopMode: (of_run_loop_mode_t)runLoopMode;
target: (id)target
selector: (SEL)selector
context: (nullable id)context;
# ifdef OF_HAVE_BLOCKS
/*!
* @brief Asynchronously writes a buffer into the stream.
*
* @note The stream must conform to @ref OFReadyForWritingObserving in order
* for this to work!
|
︙ | | |
︙ | | |
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
-
+
|
#import "OFWriteFailedException.h"
#import "of_asprintf.h"
#define MIN_READ_SIZE 512
@implementation OFStream
@synthesize of_waitingForDelimiter = _waitingForDelimiter;
@synthesize of_waitingForDelimiter = _waitingForDelimiter, delegate = _delegate;
#if defined(SIGPIPE) && defined(SIG_IGN)
+ (void)initialize
{
if (self == [OFStream class])
signal(SIGPIPE, SIG_IGN);
}
|
︙ | | |
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
|
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
|
length: length - readLength];
}
}
#ifdef OF_HAVE_SOCKETS
- (void)asyncReadIntoBuffer: (void *)buffer
length: (size_t)length
target: (id)target
selector: (SEL)selector
context: (id)context
{
[self asyncReadIntoBuffer: buffer
length: length
runLoopMode: of_run_loop_mode_default
runLoopMode: of_run_loop_mode_default];
target: target
selector: selector
context: context];
}
- (void)asyncReadIntoBuffer: (void *)buffer
length: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
target: (id)target
selector: (SEL)selector
context: (id)context
{
OFStream <OFReadyForReadingObserving> *stream =
(OFStream <OFReadyForReadingObserving> *)self;
[OFRunLoop of_addAsyncReadForStream: stream
buffer: buffer
length: length
mode: runLoopMode
target: target
selector: selector
delegate: _delegate];
context: context];
}
- (void)asyncReadIntoBuffer: (void *)buffer
exactLength: (size_t)length
target: (id)target
selector: (SEL)selector
context: (id)context
{
[self asyncReadIntoBuffer: buffer
exactLength: length
runLoopMode: of_run_loop_mode_default
runLoopMode: of_run_loop_mode_default];
target: target
selector: selector
context: context];
}
- (void)asyncReadIntoBuffer: (void *)buffer
exactLength: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
target: (id)target
selector: (SEL)selector
context: (id)context
{
OFStream <OFReadyForReadingObserving> *stream =
(OFStream <OFReadyForReadingObserving> *)self;
[OFRunLoop of_addAsyncReadForStream: stream
buffer: buffer
exactLength: length
mode: runLoopMode
target: target
selector: selector
delegate: _delegate];
context: context];
}
# ifdef OF_HAVE_BLOCKS
- (void)asyncReadIntoBuffer: (void *)buffer
length: (size_t)length
block: (of_stream_async_read_block_t)block
{
|
︙ | | |
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
|
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
|
-
+
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
|
if ([self isAtEndOfStream])
return nil;
return line;
}
#ifdef OF_HAVE_SOCKETS
- (void)asyncReadLineWithTarget: (id)target
- (void)asyncReadLine
selector: (SEL)selector
context: (id)context
{
[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
runLoopMode: of_run_loop_mode_default
runLoopMode: of_run_loop_mode_default];
target: target
selector: selector
context: context];
}
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
target: (id)target
selector: (SEL)selector
context: (id)context
{
[self asyncReadLineWithEncoding: encoding
runLoopMode: of_run_loop_mode_default
runLoopMode: of_run_loop_mode_default];
target: target
selector: selector
context: context];
}
- (void)asyncReadLineWithEncoding: (of_string_encoding_t)encoding
runLoopMode: (of_run_loop_mode_t)runLoopMode
target: (id)target
selector: (SEL)selector
context: (id)context
{
OFStream <OFReadyForReadingObserving> *stream =
(OFStream <OFReadyForReadingObserving> *)self;
[OFRunLoop of_addAsyncReadLineForStream: stream
encoding: encoding
mode: runLoopMode
target: target
selector: selector
delegate: _delegate];
context: context];
}
# ifdef OF_HAVE_BLOCKS
- (void)asyncReadLineWithBlock: (of_stream_async_read_line_block_t)block
{
[self asyncReadLineWithEncoding: OF_STRING_ENCODING_UTF_8
runLoopMode: of_run_loop_mode_default
|
︙ | | |
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
|
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
|
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
|
return length;
}
}
#ifdef OF_HAVE_SOCKETS
- (void)asyncWriteBuffer: (const void *)buffer
length: (size_t)length
target: (id)target
selector: (SEL)selector
context: (id)context
{
[self asyncWriteBuffer: buffer
length: length
runLoopMode: of_run_loop_mode_default
runLoopMode: of_run_loop_mode_default];
target: target
selector: selector
context: context];
}
- (void)asyncWriteBuffer: (const void *)buffer
length: (size_t)length
runLoopMode: (of_run_loop_mode_t)runLoopMode
target: (id)target
selector: (SEL)selector
context: (id)context
{
OFStream <OFReadyForWritingObserving> *stream =
(OFStream <OFReadyForWritingObserving> *)self;
[OFRunLoop of_addAsyncWriteForStream: stream
buffer: buffer
length: length
mode: runLoopMode
target: target
selector: selector
delegate: _delegate];
context: context];
}
# ifdef OF_HAVE_BLOCKS
- (void)asyncWriteBuffer: (const void *)buffer
length: (size_t)length
block: (of_stream_async_write_block_t)block
{
|
︙ | | |
︙ | | |
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
|
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
100
|
-
+
+
+
+
+
+
+
+
+
+
|
Class of_tls_socket_class = Nil;
static of_run_loop_mode_t connectRunLoopMode = @"of_tcp_socket_connect_mode";
static OFString *defaultSOCKS5Host = nil;
static uint16_t defaultSOCKS5Port = 1080;
@interface OFTCPSocket_AsyncConnectContext: OFObject
@interface OFTCPSocket_AsyncConnectContext: OFObject <OFStreamDelegate>
{
OFTCPSocket *_socket;
OFString *_host;
uint16_t _port;
OFString *_SOCKS5Host;
uint16_t _SOCKS5Port;
id _target;
SEL _selector;
id _context;
#ifdef OF_HAVE_BLOCKS
of_tcp_socket_async_connect_block_t _block;
#endif
id _exception;
OFData *_socketAddresses;
size_t _socketAddressesIndex;
enum {
SOCKS5_STATE_SEND_AUTHENTICATION = 1,
SOCKS5_STATE_READ_VERSION,
SOCKS5_STATE_SEND_REQUEST,
SOCKS5_STATE_READ_RESPONSE,
SOCKS5_STATE_READ_ADDRESS,
SOCKS5_STATE_READ_ADDRESS_LENGTH,
} _SOCKS5State;
/* Longest read is domain name (max 255 bytes) + port */
unsigned char _buffer[257];
OFMutableData *_request;
}
- (instancetype)initWithSocket: (OFTCPSocket *)sock
host: (OFString *)host
port: (uint16_t)port
SOCKS5Host: (OFString *)SOCKS5Host
SOCKS5Port: (uint16_t)SOCKS5Port
|
︙ | | |
108
109
110
111
112
113
114
115
116
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
|
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
- (void)resolver: (OFDNSResolver *)resolver
didResolveDomainName: (OFString *)domainName
socketAddresses: (OFData *)socketAddresses
context: (id)context
exception: (id)exception;
- (void)startWithRunLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)sendSOCKS5Request;
- (size_t)socket: (OFTCPSocket *)sock
didSendSOCKS5Authentication: (const void *)request
bytesWritten: (size_t)bytesWritten
context: (id)context
exception: (id)exception;
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKSVersion: (unsigned char *)SOCKSVersion
length: (size_t)length
context: (id)context
exception: (id)exception;
- (size_t)socket: (OFTCPSocket *)sock
didSendSOCKS5Request: (const void *)request
bytesWritten: (size_t)bytesWritten
context: (id)context
exception: (id)exception;
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKS5Response: (unsigned char *)response
length: (size_t)length
context: (id)context
exception: (id)exception;
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKS5Address: (unsigned char *)address
length: (size_t)length
context: (id)context
exception: (id)exception;
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKS5AddressLength: (unsigned char *)addressLength
length: (size_t)length
context: (id)context
exception: (id)exception;
@end
@interface OFTCPSocket_ConnectContext: OFObject
{
@public
bool _done;
id _exception;
|
︙ | | |
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
+
+
|
_host = [host copy];
_port = port;
_SOCKS5Host = [SOCKS5Host copy];
_SOCKS5Port = SOCKS5Port;
_target = [target retain];
_selector = selector;
_context = [context retain];
[_socket setDelegate: self];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
|
︙ | | |
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
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
224
225
|
+
+
+
+
+
+
|
return self;
}
#endif
- (void)dealloc
{
if ([_socket delegate] == self)
[_socket setDelegate: nil];
[_socket release];
[_host release];
[_SOCKS5Host release];
[_target release];
[_context release];
#ifdef OF_HAVE_BLOCKS
[_block release];
#endif
[_exception release];
[_socketAddresses release];
[_request release];
[super dealloc];
}
- (void)didConnect
{
[_socket setDelegate: nil];
if (_exception == nil)
[_socket setBlocking: true];
#ifdef OF_HAVE_BLOCKS
if (_block != NULL)
_block(_socket, _exception);
else {
|
︙ | | |
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
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
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
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
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
|
376
377
378
379
380
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
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
|
+
-
+
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
|
socketAddresses:context:
exception:)
context: nil];
}
- (void)sendSOCKS5Request
{
_SOCKS5State = SOCKS5_STATE_SEND_AUTHENTICATION;
[_socket asyncWriteBuffer: "\x05\x01\x00"
length: 3
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]];
target: self
selector: @selector(socket:didSendSOCKS5Authentication:
bytesWritten:context:exception:)
context: nil];
}
- (size_t)socket: (OFTCPSocket *)sock
didSendSOCKS5Authentication: (const void *)request
bytesWritten: (size_t)bytesWritten
- (bool)stream: (OF_KINDOF(OFStream *))sock
didReadIntoBuffer: (void *)buffer
length: (size_t)length
context: (id)context
exception: (id)exception
{
if (exception != nil) {
_exception = [exception retain];
[self didConnect];
return 0;
}
of_run_loop_mode_t runLoopMode =
[_socket asyncReadIntoBuffer: _buffer
exactLength: 2
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]
[[OFRunLoop currentRunLoop] currentMode];
target: self
selector: @selector(socket:didReadSOCKSVersion:
length:context:exception:)
context: nil];
return 0;
}
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKSVersion: (unsigned char *)SOCKSVersion
unsigned char *SOCKSVersion;
length: (size_t)length
context: (id)context
exception: (id)exception
{
OFMutableData *request;
uint8_t hostLength;
unsigned char port[2];
unsigned char *response, *addressLength;
if (exception != nil) {
_exception = [exception retain];
[self didConnect];
return false;
}
switch (_SOCKS5State) {
case SOCKS5_STATE_READ_VERSION:
SOCKSVersion = buffer;
if (SOCKSVersion[0] != 5 || SOCKSVersion[1] != 0) {
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
if (SOCKSVersion[0] != 5 || SOCKSVersion[1] != 0) {
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
[_request release];
request = [OFMutableData data];
[request addItems: "\x05\x01\x00\x03"
count: 4];
_request = [[OFMutableData alloc] init];
[_request addItems: "\x05\x01\x00\x03"
count: 4];
hostLength = (uint8_t)[_host UTF8StringLength];
[request addItem: &hostLength];
[request addItems: [_host UTF8String]
count: hostLength];
hostLength = (uint8_t)[_host UTF8StringLength];
[_request addItem: &hostLength];
[_request addItems: [_host UTF8String]
count: hostLength];
port[0] = _port >> 8;
port[1] = _port & 0xFF;
[request addItems: port
count: 2];
/* Use request as context to retain it */
[_socket asyncWriteBuffer: [request items]
length: [request count]
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]
target: self
selector: @selector(socket:didSendSOCKS5Request:
bytesWritten:context:exception:)
context: request];
return false;
}
- (size_t)socket: (OFTCPSocket *)sock
didSendSOCKS5Request: (const void *)request
bytesWritten: (size_t)bytesWritten
context: (id)context
exception: (id)exception
{
if (exception != nil) {
_exception = [exception retain];
[self didConnect];
return 0;
}
[_socket asyncReadIntoBuffer: _buffer
exactLength: 4
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]
port[0] = _port >> 8;
port[1] = _port & 0xFF;
[_request addItems: port
count: 2];
_SOCKS5State = SOCKS5_STATE_SEND_REQUEST;
[_socket asyncWriteBuffer: [_request items]
length: [_request count]
runLoopMode: runLoopMode];
target: self
selector: @selector(socket:didReadSOCKS5Response:
length:context:exception:)
context: nil];
return 0;
return false;
}
case SOCKS5_STATE_READ_RESPONSE:
- (bool)socket: (OFTCPSocket *)sock
didReadSOCKS5Response: (unsigned char *)response
length: (size_t)length
context: (id)context
exception: (id)exception
{
of_run_loop_mode_t runLoopMode;
response = buffer;
if (exception != nil) {
_exception = [exception retain];
[self didConnect];
return false;
}
if (response[0] != 5 || response[2] != 0) {
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
if (response[0] != 5 || response[2] != 0) {
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
if (response[1] != 0) {
int errNo;
if (response[1] != 0) {
int errNo;
switch (response[1]) {
case 0x02:
errNo = EACCES;
break;
case 0x03:
errNo = ENETUNREACH;
break;
case 0x04:
errNo = EHOSTUNREACH;
break;
case 0x05:
errNo = ECONNREFUSED;
break;
case 0x06:
errNo = ETIMEDOUT;
break;
case 0x07:
errNo = EPROTONOSUPPORT;
break;
case 0x08:
errNo = EAFNOSUPPORT;
break;
default:
errNo = EPROTO;
break;
}
switch (response[1]) {
case 0x02:
errNo = EACCES;
break;
case 0x03:
errNo = ENETUNREACH;
break;
case 0x04:
errNo = EHOSTUNREACH;
break;
case 0x05:
errNo = ECONNREFUSED;
break;
case 0x06:
errNo = ETIMEDOUT;
break;
case 0x07:
errNo = EPROTONOSUPPORT;
break;
case 0x08:
errNo = EAFNOSUPPORT;
break;
default:
errNo = EPROTO;
break;
}
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: _socket
errNo: errNo];
[self didConnect];
return false;
}
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: _socket
errNo: errNo];
[self didConnect];
return false;
}
runLoopMode = [[OFRunLoop currentRunLoop] currentMode];
/* Skip the rest of the response */
switch (response[3]) {
case 1: /* IPv4 */
[_socket asyncReadIntoBuffer: _buffer
exactLength: 4 + 2
runLoopMode: runLoopMode
/* Skip the rest of the response */
switch (response[3]) {
case 1: /* IPv4 */
_SOCKS5State = SOCKS5_STATE_READ_ADDRESS;
[_socket asyncReadIntoBuffer: _buffer
exactLength: 4 + 2
runLoopMode: runLoopMode];
target: self
selector: @selector(socket:
didReadSOCKS5Address:length:
context:exception:)
context: nil];
return false;
case 3: /* Domain name */
[_socket asyncReadIntoBuffer: _buffer
exactLength: 1
runLoopMode: runLoopMode
return false;
case 3: /* Domain name */
_SOCKS5State = SOCKS5_STATE_READ_ADDRESS_LENGTH;
[_socket asyncReadIntoBuffer: _buffer
exactLength: 1
runLoopMode: runLoopMode];
target: self
selector: @selector(socket:
didReadSOCKS5AddressLength:
length:context:exception:)
context: nil];
return false;
case 4: /* IPv6 */
[_socket asyncReadIntoBuffer: _buffer
return false;
case 4: /* IPv6 */
_SOCKS5State = SOCKS5_STATE_READ_ADDRESS;
[_socket asyncReadIntoBuffer: _buffer
exactLength: 16 + 2
runLoopMode: runLoopMode
runLoopMode: runLoopMode];
target: self
selector: @selector(socket:
didReadSOCKS5Address:length:
context:exception:)
context: nil];
return false;
default:
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
return false;
default:
_exception = [[OFConnectionFailedException alloc]
initWithHost: _host
port: _port
socket: self
errNo: EPROTONOSUPPORT];
[self didConnect];
return false;
}
return false;
}
- (bool)socket: (OFTCPSocket *)sock
return false;
case SOCKS5_STATE_READ_ADDRESS:
[self didConnect];
return false;
case SOCKS5_STATE_READ_ADDRESS_LENGTH:
addressLength = buffer;
_SOCKS5State = SOCKS5_STATE_READ_ADDRESS;
[_socket asyncReadIntoBuffer: _buffer
exactLength: addressLength[0] + 2
runLoopMode: runLoopMode];
return false;
default:
assert(0);
return false;
}
}
didReadSOCKS5Address: (unsigned char *)address
length: (size_t)length
- (size_t)stream: (OF_KINDOF(OFStream *))sock
didWriteBuffer: (const void **)buffer
length: (size_t)length
context: (id)context
exception: (id)exception
{
_exception = [exception retain];
[self didConnect];
return false;
}
- (bool)socket: (OFTCPSocket *)sock
of_run_loop_mode_t runLoopMode =
[[OFRunLoop currentRunLoop] currentMode];
switch (_SOCKS5State) {
case SOCKS5_STATE_SEND_AUTHENTICATION:
_SOCKS5State = SOCKS5_STATE_READ_VERSION;
[_socket asyncReadIntoBuffer: _buffer
didReadSOCKS5AddressLength: (unsigned char *)addressLength
length: (size_t)length
context: (id)context
exactLength: 2
runLoopMode: runLoopMode];
exception: (id)exception
{
if (exception != nil) {
_exception = [exception retain];
[self didConnect];
return false;
}
[_socket asyncReadIntoBuffer: _buffer
exactLength: addressLength[0] + 2
runLoopMode: [[OFRunLoop currentRunLoop] currentMode]
target: self
return 0;
case SOCKS5_STATE_SEND_REQUEST:
[_request release];
_request = nil;
_SOCKS5State = SOCKS5_STATE_READ_RESPONSE;
[_socket asyncReadIntoBuffer: _buffer
exactLength: 4
runLoopMode: runLoopMode];
return 0;
selector: @selector(socket:didReadSOCKS5Address:
length:context:exception:)
context: nil];
return false;
default:
assert(0);
return 0;
}
}
- (void)stream: (OF_KINDOF(OFStream *))sock
didFailWithException: (id)exception
{
_exception = [exception retain];
[self didConnect];
}
@end
@implementation OFTCPSocket_ConnectContext
- (void)dealloc
{
[_exception release];
|
︙ | | |
︙ | | |
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
-
+
+
|
#import "ProgressBar.h"
#define GIBIBYTE (1024 * 1024 * 1024)
#define MEBIBYTE (1024 * 1024)
#define KIBIBYTE (1024)
@interface OFHTTP: OFObject <OFApplicationDelegate, OFHTTPClientDelegate>
@interface OFHTTP: OFObject <OFApplicationDelegate, OFHTTPClientDelegate,
OFStreamDelegate>
{
OFArray OF_GENERIC(OFString *) *_URLs;
size_t _URLIndex;
int _errorCode;
OFString *_outputPath, *_currentFileName;
bool _continue, _force, _detectFileName, _detectedFileName;
bool _quiet, _verbose, _insecure;
|
︙ | | |
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
|
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
|
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
|
} else
@throw e;
[self performSelector: @selector(downloadNextURL)
afterDelay: 0];
}
- (bool)stream: (OFHTTPResponse *)response
- (bool)stream: (OF_KINDOF(OFStream *))response
didReadIntoBuffer: (void *)buffer
length: (size_t)length
context: (id)context
exception: (OFException *)e
{
if (e != nil) {
OFString *URL;
[_progressBar stop];
[_progressBar draw];
[_progressBar release];
_progressBar = nil;
if (!_quiet)
[of_stdout writeString: @"\n Error!\n"];
URL = [_URLs objectAtIndex: _URLIndex - 1];
[of_stderr writeLine:
OF_LOCALIZED(@"download_failed_exception",
@"%[prog]: Failed to download <%[url]>: %[exception]",
@"prog", [OFApplication programName],
@"url", URL,
@"exception", e)];
_errorCode = 1;
goto next;
}
_received += length;
[_output writeBuffer: buffer
length: length];
[_progressBar setReceived: _received];
if ([response isAtEndOfStream] ||
(_length >= 0 && _received >= _length)) {
[_progressBar stop];
[_progressBar draw];
[_progressBar release];
_progressBar = nil;
if (!_quiet) {
[of_stdout writeString: @"\n "];
[of_stdout writeLine:
OF_LOCALIZED(@"download_done", @"Done!")];
}
goto next;
[self performSelector: @selector(downloadNextURL)
afterDelay: 0];
return false;
}
return true;
next:
}
- (void)stream: (OF_KINDOF(OFStream *))response
didFailWithException: (id)exception
{
OFString *URL;
[_progressBar stop];
[_progressBar draw];
[_progressBar release];
_progressBar = nil;
if (!_quiet)
[of_stdout writeString: @"\n Error!\n"];
URL = [_URLs objectAtIndex: _URLIndex - 1];
[of_stderr writeLine: OF_LOCALIZED(
@"download_failed_exception",
@"%[prog]: Failed to download <%[url]>: %[exception]",
@"prog", [OFApplication programName],
@"url", URL,
@"exception", exception)];
_errorCode = 1;
[self performSelector: @selector(downloadNextURL)
afterDelay: 0];
return false;
}
- (void)client: (OFHTTPClient *)client
didReceiveHeaders: (OFDictionary OF_GENERIC(OFString *, OFString *) *)headers
statusCode: (int)statusCode
request: (OFHTTPRequest *)request
context: (id)context
|
︙ | | |
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
|
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
|
+
-
+
-
-
-
-
-
|
[_progressBar setReceived: _received];
[_progressBar draw];
}
[_currentFileName release];
_currentFileName = nil;
[response setDelegate: self];
[response asyncReadIntoBuffer: _buffer
length: [OFSystemInfo pageSize]
length: [OFSystemInfo pageSize]];
target: self
selector: @selector(stream:didReadIntoBuffer:
length:context:exception:)
context: nil];
return;
next:
[_currentFileName release];
_currentFileName = nil;
[self performSelector: @selector(downloadNextURL)
|
︙ | | |