ObjFW  Diff

Differences From Artifact [7cb45bbee2]:

To Artifact [fe26303808]:

  • File src/OFHTTPServer.m — part of check-in [d16ad96cbd] at 2018-12-07 01:33:47 on branch trunk — OFStream: Use a delegate for async operations

    The target / selector approach had several drawbacks:

    * It was inconvenient to use, as for every read or write, a target,
    selector and context would need to be specified.
    * It lacked any kind of type-safety and would not even warn about using
    a callback method with the wrong number of parameters.
    * It encouraged using a different callback method for each read or
    write call, which results in code that is hard to follow and also
    slower (as it needs to recreate the async operation with a new
    callback every time). (user: js, size: 17752) [annotate] [blame] [check-ins using]


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
	  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
{
@public
	OF_KINDOF(OFTCPSocket *) _socket;
	OFHTTPServer *_server;
	OFTimer *_timer;
	enum {
		AWAITING_PROLOG,







|
|

















|







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: (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 <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
	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>







<
<
<
<







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)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
	[_path release];
	[_headers release];
	[_requestBody release];

	[super dealloc];
}

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

	@try {
		switch (_state) {
		case AWAITING_PROLOG:
			return [self parseProlog: line];
		case PARSING_HEADERS:







|

<
<

|







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)stream: (OF_KINDOF(OFStream *))sock
   didReadLine: (OFString *)line


{
	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
- (void)stop
{
	[_listeningSocket cancelAsyncRequests];
	[_listeningSocket release];
	_listeningSocket = nil;
}

- (bool)of_socket: (OF_KINDOF(OFTCPSocket *))sock
  didAcceptSocket: (OF_KINDOF(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 asyncReadLineWithTarget: connection
				     selector: @selector(socket:didReadLine:
						  context:exception:)
				      context: nil];

	return true;
}
@end







|
|


















>
|
<
<
<




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: (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 asyncReadLine];




	return true;
}
@end