ObjFW  Check-in [e833a8b212]

Overview
Comment:OFHTTP{Client,Server}: Reject empty Content-Length
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e833a8b2120c8eb2a6f496ab34e122ae75c98c8ef966ea502132734e37af60f5
User & Date: js on 2020-03-29 14:04:45
Other Links: manifest | tags
Context
2020-03-29
16:57
Add fish completion for ofdns check-in: b13594ccc6 user: js tags: trunk
14:04
OFHTTP{Client,Server}: Reject empty Content-Length check-in: e833a8b212 user: js tags: trunk
03:05
OFHTTPClient: Minor chunked body improvement check-in: d9350dba53 user: js tags: trunk
Changes

Modified src/OFHTTPClient.m from [4db698c7b0] to [d88637be29].

116
117
118
119
120
121
122

123
124
125
126
127
128
129
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130







+







	void *pool = objc_autoreleasePoolPush();
	of_http_request_method_t method = request.method;
	OFURL *URL = request.URL;
	OFString *path;
	OFString *user = URL.user, *password = URL.password;
	OFMutableString *requestString;
	OFMutableDictionary OF_GENERIC(OFString *, OFString *) *headers;
	bool hasContentLength, chunked;
	OFEnumerator OF_GENERIC(OFString *) *keyEnumerator, *objectEnumerator;
	OFString *key, *object;

	if (URL.path != nil)
		path = URL.URLEncodedPath;
	else
		path = @"/";
183
184
185
186
187
188
189
190





191
192
193
194
195
196
197
184
185
186
187
188
189
190

191
192
193
194
195
196
197
198
199
200
201
202







-
+
+
+
+
+








	if (request.protocolVersion.major == 1 &&
	    request.protocolVersion.minor == 0 &&
	    [headers objectForKey: @"Connection"] == nil)
		[headers setObject: @"keep-alive"
			    forKey: @"Connection"];

	if ([headers objectForKey: @"Content-Length"] != nil &&
	hasContentLength = ([headers objectForKey: @"Content-Length"] != nil);
	chunked = [[headers objectForKey: @"Transfer-Encoding"]
	    isEqual: @"chunked"];

	if ((hasContentLength || chunked) &&
	    [headers objectForKey: @"Content-Type"] == nil)
		[headers setObject: @"application/x-www-form-"
				    @"urlencoded; charset=UTF-8"
			    forKey: @"Content-Type"];

	keyEnumerator = [headers keyEnumerator];
	objectEnumerator = [headers objectEnumerator];
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
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







-
+

















-
+
+

-
-
+







- (OFString *)stream: (OFStream *)stream
      didWriteString: (OFString *)string
	    encoding: (of_string_encoding_t)encoding
	bytesWritten: (size_t)bytesWritten
	   exception: (id)exception
{
	OFDictionary OF_GENERIC(OFString *, OFString *) *headers;
	OFString *transferEncoding;
	bool chunked;

	if (exception != nil) {
		if ([exception isKindOfClass: [OFWriteFailedException class]] &&
		    ([exception errNo] == ECONNRESET ||
		    [exception errNo] == EPIPE)) {
			/* In case a keep-alive connection timed out */
			[self closeAndReconnect];
			return nil;
		}

		[self raiseException: exception];
		return nil;
	}

	_firstLine = true;

	headers = _request.headers;
	transferEncoding = [headers objectForKey: @"Transfer-Encoding"];
	chunked = [[headers objectForKey: @"Transfer-Encoding"]
	    isEqual: @"chunked"];

	if ([transferEncoding isEqual: @"chunked"] ||
	    [headers objectForKey: @"Content-Length"] != nil) {
	if (chunked || [headers objectForKey: @"Content-Length"] != nil) {
		stream.delegate = nil;

		OFStream *requestBody = [[[OFHTTPClientRequestBodyStream alloc]
		    initWithHandler: self
			     socket: (OFTCPSocket *)stream] autorelease];

		if ([_client->_delegate respondsToSelector:
721
722
723
724
725
726
727
728

729
730
731
732
733
734
735
726
727
728
729
730
731
732

733
734
735
736
737
738
739
740







-
+







		headers = _handler->_request.headers;

		transferEncoding = [headers objectForKey: @"Transfer-Encoding"];
		_chunked = [transferEncoding isEqual: @"chunked"];

		contentLengthString = [headers objectForKey: @"Content-Length"];
		if (contentLengthString != nil) {
			if (_chunked)
			if (_chunked || contentLengthString.length == 0)
				@throw [OFInvalidArgumentException
				    exception];

			contentLength = contentLengthString.decimalValue;
			if (contentLength < 0)
				@throw [OFOutOfRangeException exception];

865
866
867
868
869
870
871
872

873
874
875
876
877
878
879
870
871
872
873
874
875
876

877
878
879
880
881
882
883
884







-
+







	super.headers = headers;

	_chunked = [[headers objectForKey: @"Transfer-Encoding"]
	    isEqual: @"chunked"];

	contentLength = [headers objectForKey: @"Content-Length"];
	if (contentLength != nil) {
		if (_chunked)
		if (_chunked || contentLength.length == 0)
			@throw [OFInvalidServerReplyException exception];

		_hasContentLength = true;

		@try {
			_toRead = contentLength.decimalValue;

999
1000
1001
1002
1003
1004
1005
1006

1007
1008
1009
1010
1011
1012
1013
1014
1004
1005
1006
1007
1008
1009
1010

1011

1012
1013
1014
1015
1016
1017
1018







-
+
-







				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidServerReplyException
				    exception];
		}

		@try {
			_toRead = line.hexadecimalValue;
			if ((_toRead = line.hexadecimalValue) < 0)
			if (_toRead < 0)
				@throw [OFOutOfRangeException exception];
		} @catch (OFInvalidFormatException *e) {
			@throw [OFInvalidServerReplyException exception];
		}

		if (_toRead == 0) {
			_setAtEndOfStream = true;

Modified src/OFHTTPServer.m from [b25900c5f7] to [0402f29968].

411
412
413
414
415
416
417
418

419
420
421
422
423
424
425
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425







-
+







		bool chunked = [[_headers objectForKey: @"Transfer-Encoding"]
		    isEqual: @"chunked"];
		OFString *contentLengthString =
		    [_headers objectForKey: @"Content-Length"];
		intmax_t contentLength = 0;

		if (contentLengthString != nil) {
			if (chunked)
			if (chunked || contentLengthString.length == 0)
				return [self sendErrorAndClose: 400];

			@try {
				contentLength =
				    contentLengthString.decimalValue;
			} @catch (OFInvalidFormatException *e) {
				return [self sendErrorAndClose: 400];
715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730
715
716
717
718
719
720
721

722

723
724
725
726
727
728
729







-
+
-







			if (_socket.atEndOfStream &&
			    range.location == OF_NOT_FOUND)
				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidFormatException exception];
		}

		_toRead = line.hexadecimalValue;
		if ((_toRead = line.hexadecimalValue) < 0)
		if (_toRead < 0)
			@throw [OFOutOfRangeException exception];

		if (_toRead == 0) {
			_setAtEndOfStream = true;
			_toRead = -2;
		}