ObjFW  Diff

Differences From Artifact [da5c2f66e5]:

To Artifact [cd147444d1]:


24
25
26
27
28
29
30



31
32
33
34
35
36
37
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40







+
+
+







#import "OFFile.h"
#import "OFFileManager.h"
#import "OFHTTPClient.h"
#import "OFHTTPRequest.h"
#import "OFHTTPResponse.h"
#import "OFLocale.h"
#import "OFOptionsParser.h"
#ifdef OF_HAVE_PLUGINS
# import "OFPlugin.h"
#endif
#import "OFSandbox.h"
#import "OFStdIOStream.h"
#import "OFSystemInfo.h"
#import "OFTCPSocket.h"
#import "OFTLSSocket.h"
#import "OFURL.h"

65
66
67
68
69
70
71
72

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

75
76
77
78
79
80
81
82







-
+







	bool _detectedFileName, _quiet, _verbose, _insecure;
	OFStream *_body;
	of_http_request_method_t _method;
	OFMutableDictionary *_clientHeaders;
	OFHTTPClient *_HTTPClient;
	char *_buffer;
	OFStream *_output;
	intmax_t _received, _length, _resumedFrom;
	unsigned long long _received, _length, _resumedFrom;
	ProgressBar *_progressBar;
}

- (void)downloadNextURL;
@end

OF_APPLICATION_DELEGATE(OFHTTP)
270
271
272
273
274
275
276











277
278
279
280
281
282
283
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







+
+
+
+
+
+
+
+
+
+
+








	[fileName retain];
	objc_autoreleasePoolPop(pool);
	return [fileName autorelease];
}

@implementation OFHTTP
#ifdef OF_HAVE_PLUGINS
+ (void)initialize
{
	if (self != [OFHTTP class])
		return;

	/* Opportunistically try loading ObjOpenSSL and ignore any errors. */
	of_dlopen(@"objopenssl", OF_RTLD_LAZY);
}
#endif

- (instancetype)init
{
	self = [super init];

	@try {
		_method = OF_HTTP_REQUEST_METHOD_GET;

330
331
332
333
334
335
336

337

338
339
340
341
342
343
344
344
345
346
347
348
349
350
351

352
353
354
355
356
357
358
359







+
-
+







	if ([path isEqual: @"-"])
		_body = [of_stdin copy];
	else {
		_body = [[OFFile alloc] initWithPath: path
						mode: @"r"];

		@try {
			unsigned long long fileSize =
			uintmax_t fileSize = [[OFFileManager defaultManager]
			    [[OFFileManager defaultManager]
			    attributesOfItemAtPath: path].fileSize;

			contentLength =
			    [OFString stringWithFormat: @"%ju", fileSize];
			[_clientHeaders setObject: contentLength
					   forKey: @"Content-Length"];
		} @catch (OFRetrieveItemAttributesFailedException *e) {
372
373
374
375
376
377
378
379

380
381
382
383
384
385
386


387
388
389
390
391
392
393
387
388
389
390
391
392
393

394
395
396
397
398
399


400
401
402
403
404
405
406
407
408







-
+





-
-
+
+







- (void)setProxy: (OFString *)proxy
{
	@try {
		size_t pos = [proxy
		    rangeOfString: @":"
			  options: OF_STRING_SEARCH_BACKWARDS].location;
		OFString *host;
		intmax_t port;
		unsigned long long port;

		if (pos == OF_NOT_FOUND)
			@throw [OFInvalidFormatException exception];

		host = [proxy substringWithRange: of_range(0, pos)];
		port = [proxy substringWithRange:
		    of_range(pos + 1, proxy.length - pos - 1)].decimalValue;
		port = [proxy substringWithRange: of_range(pos + 1,
		    proxy.length - pos - 1)].unsignedLongLongValue;

		if (port > UINT16_MAX)
			@throw [OFOutOfRangeException exception];

		[OFTCPSocket setSOCKS5Host: host];
		[OFTCPSocket setSOCKS5Port: (uint16_t)port];
	} @catch (OFInvalidFormatException *e) {
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
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







-
+








-
+


-
+







	[OFLocale addLanguageDirectory: @"PROGDIR:/share/ofhttp/lang"];
#endif

	optionsParser = [OFOptionsParser parserWithOptions: options];
	while ((option = [optionsParser nextOption]) != '\0') {
		switch (option) {
		case 'b':
			self.body = optionsParser.argument;
			[self setBody: optionsParser.argument];
			break;
		case 'h':
			help(of_stdout, true, 0);
			break;
		case 'H':
			[self addHeader: optionsParser.argument];
			break;
		case 'm':
			self.method = optionsParser.argument;
			[self setMethod: optionsParser.argument];
			break;
		case 'P':
			self.proxy = optionsParser.argument;
			[self setProxy: optionsParser.argument];
			break;
		case ':':
			if (optionsParser.lastLongOption != nil)
				[of_stderr writeLine:
				    OF_LOCALIZED(@"long_argument_missing",
				    @"%[prog]: Argument for option --%[opt] "
				    @"missing"
717
718
719
720
721
722
723
724
725





726
727
728
729
730
731
732
732
733
734
735
736
737
738


739
740
741
742
743
744
745
746
747
748
749
750







-
-
+
+
+
+
+







		OFString *URL;

		[_progressBar stop];
		[_progressBar draw];
		[_progressBar release];
		_progressBar = nil;

		if (!_quiet)
			[of_stdout writeString: @"\n  Error!\n"];
		if (!_quiet) {
			[of_stdout writeString: @"\n  "];
			[of_stdout writeLine: OF_LOCALIZED(@"download_error",
			    @"Error!")];
		}

		URL = [_URLs objectAtIndex: _URLIndex - 1];
		[of_stderr writeLine: OF_LOCALIZED(
		    @"download_failed_exception",
		    @"%[prog]: Failed to download <%[url]>!\n"
		    @"  %[exception]",
		    @"prog", [OFApplication programName],
740
741
742
743
744
745
746
747

748
749
750
751
752
753
754
758
759
760
761
762
763
764

765
766
767
768
769
770
771
772







-
+







	}

	_received += length;

	[_output writeBuffer: buffer
		      length: length];

	_progressBar.received = _received;
	[_progressBar setReceived: _received];

	if (response.atEndOfStream) {
		[_progressBar stop];
		[_progressBar draw];
		[_progressBar release];
		_progressBar = nil;

781
782
783
784
785
786
787
788

789
790
791
792
793
794
795
799
800
801
802
803
804
805

806
807
808
809
810
811
812
813







-
+








		[of_stdout writeFormat: @" ➜ %d\n", statusCode];

		if (type == nil)
			type = OF_LOCALIZED(@"type_unknown", @"unknown");

		if (lengthString != nil) {
			_length = lengthString.decimalValue;
			_length = lengthString.unsignedLongLongValue;

			if (_resumedFrom + _length >= GIBIBYTE) {
				lengthString = [OFString stringWithFormat:
				    @"%,.2f",
				    (float)(_resumedFrom + _length) / GIBIBYTE];
				lengthString = OF_LOCALIZED(@"size_gib",
				    @"%[num] GiB",
808
809
810
811
812
813
814
815
816
817
818
819
820






821
822
823
824
825
826
827
826
827
828
829
830
831
832






833
834
835
836
837
838
839
840
841
842
843
844
845







-
-
-
-
-
-
+
+
+
+
+
+







				lengthString = OF_LOCALIZED(@"size_kib",
				    @"%[num] KiB",
				    @"num", lengthString);
			} else {
				lengthString = [OFString stringWithFormat:
				    @"%jd", _resumedFrom + _length];
				lengthString = OF_LOCALIZED(@"size_bytes",
				    [@"["
				     @"    ["
				     @"        {'num == 1': '1 byte'},"
				     @"        {'': '%[num] bytes'}"
				     @"    ]"
				     @"]" JSONValue],
				    @"["
				    @"    ["
				    @"        {'num == 1': '1 byte'},"
				    @"        {'': '%[num] bytes'}"
				    @"    ]"
				    @"]".objectByParsingJSON,
				    @"num", lengthString);
			}
		} else
			lengthString =
			    OF_LOCALIZED(@"size_unknown", @"unknown");

		if (_verbose) {
918
919
920
921
922
923
924
925

926
927
928
929
930
931
932
936
937
938
939
940
941
942

943
944
945
946
947
948
949
950







-
+







		}
	}

	if (!_quiet) {
		_progressBar = [[ProgressBar alloc]
		    initWithLength: _length
		       resumedFrom: _resumedFrom];
		_progressBar.received = _received;
		[_progressBar setReceived: _received];
		[_progressBar draw];
	}

	[_currentFileName release];
	_currentFileName = nil;

	response.delegate = self;
1006
1007
1008
1009
1010
1011
1012

1013

1014
1015
1016
1017

1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035

1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046







+
-
+



-
+


-
+







		_currentFileName = [_outputPath copy];

	if (_currentFileName == nil)
		_currentFileName = [URL.path.lastPathComponent copy];

	if (_continue) {
		@try {
			unsigned long long size =
			uintmax_t size = [[OFFileManager defaultManager]
			    [[OFFileManager defaultManager]
			    attributesOfItemAtPath: _currentFileName].fileSize;
			OFString *range;

			if (size > INTMAX_MAX)
			if (size > ULLONG_MAX)
				@throw [OFOutOfRangeException exception];

			_resumedFrom = (intmax_t)size;
			_resumedFrom = (unsigned long long)size;

			range = [OFString stringWithFormat: @"bytes=%jd-",
							    _resumedFrom];
			[clientHeaders setObject: range
					  forKey: @"Range"];
		} @catch (OFRetrieveItemAttributesFailedException *e) {
		}