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
...
183
184
185
186
187
188
189
190




191
192
193
194
195
196
197
...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
...
567
568
569
570
571
572
573
574

575
576
577
578
579
580
581
582
583
584
...
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
	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;

	OFEnumerator OF_GENERIC(OFString *) *keyEnumerator, *objectEnumerator;
	OFString *key, *object;

	if (URL.path != nil)
		path = URL.URLEncodedPath;
	else
		path = @"/";
................................................................................

	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 &&




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

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

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

	_firstLine = true;

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


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

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

		if ([_client->_delegate respondsToSelector:
................................................................................
		headers = _handler->_request.headers;

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

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

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

................................................................................
	super.headers = headers;

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

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

		_hasContentLength = true;

		@try {
			_toRead = contentLength.decimalValue;

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

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

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







>







 







|
>
>
>
>







 







|







 







|
>

<
|







 







|







 







|







 







|
<







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
...
572
573
574
575
576
577
578
579
580
581

582
583
584
585
586
587
588
589
...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
....
1004
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014
1015
1016
1017
1018
	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 = @"/";
................................................................................

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

	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];
................................................................................
- (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;
	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];
................................................................................
		[self raiseException: exception];
		return nil;
	}

	_firstLine = true;

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


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

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

		if ([_client->_delegate respondsToSelector:
................................................................................
		headers = _handler->_request.headers;

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

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

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

................................................................................
	super.headers = headers;

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

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

		_hasContentLength = true;

		@try {
			_toRead = contentLength.decimalValue;

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

		@try {
			if ((_toRead = line.hexadecimalValue) < 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
...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
		bool chunked = [[_headers objectForKey: @"Transfer-Encoding"]
		    isEqual: @"chunked"];
		OFString *contentLengthString =
		    [_headers objectForKey: @"Content-Length"];
		intmax_t contentLength = 0;

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

			@try {
				contentLength =
				    contentLengthString.decimalValue;
			} @catch (OFInvalidFormatException *e) {
				return [self sendErrorAndClose: 400];
................................................................................
			if (_socket.atEndOfStream &&
			    range.location == OF_NOT_FOUND)
				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidFormatException exception];
		}

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

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








|







 







|
<







411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
...
715
716
717
718
719
720
721
722

723
724
725
726
727
728
729
		bool chunked = [[_headers objectForKey: @"Transfer-Encoding"]
		    isEqual: @"chunked"];
		OFString *contentLengthString =
		    [_headers objectForKey: @"Content-Length"];
		intmax_t contentLength = 0;

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

			@try {
				contentLength =
				    contentLengthString.decimalValue;
			} @catch (OFInvalidFormatException *e) {
				return [self sendErrorAndClose: 400];
................................................................................
			if (_socket.atEndOfStream &&
			    range.location == OF_NOT_FOUND)
				@throw [OFTruncatedDataException exception];
			else
				@throw [OFInvalidFormatException exception];
		}

		if ((_toRead = line.hexadecimalValue) < 0)

			@throw [OFOutOfRangeException exception];

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