ObjFW  Diff

Differences From Artifact [d2c22eea59]:

To Artifact [7cb45bbee2]:


24
25
26
27
28
29
30

31
32
33
34
35
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
24
25
26
27
28
29
30
31
32
33
34
35
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







+









+












-
-
+
+






-
+





-
+







-
+
















-
+

-
+











-
+




-
+







#import "OFData.h"
#import "OFDate.h"
#import "OFDictionary.h"
#import "OFHTTPRequest.h"
#import "OFHTTPResponse.h"
#import "OFNumber.h"
#import "OFTCPSocket.h"
#import "OFTLSSocket.h"
#import "OFTimer.h"
#import "OFURL.h"

#import "OFAlreadyConnectedException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFNotOpenException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"
#import "OFUnsupportedProtocolException.h"
#import "OFWriteFailedException.h"

#import "socket_helpers.h"

#define BUFFER_SIZE 1024

/*
 * 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
- (bool)of_socket: (OF_KINDOF(OFTCPSocket *))sock
  didAcceptSocket: (OF_KINDOF(OFTCPSocket *))clientSocket
	  context: (id)context
	exception: (id)exception;
@end

@interface OFHTTPServerResponse: OFHTTPResponse <OFReadyForWritingObserving>
{
	OFTCPSocket *_socket;
	OF_KINDOF(OFTCPSocket *) _socket;
	OFHTTPServer *_server;
	OFHTTPRequest *_request;
	bool _chunked, _headersSent;
}

- (instancetype)initWithSocket: (OFTCPSocket *)sock
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
			server: (OFHTTPServer *)server
		       request: (OFHTTPRequest *)request;
@end

@interface OFHTTPServer_Connection: OFObject
{
@public
	OFTCPSocket *_socket;
	OF_KINDOF(OFTCPSocket *) _socket;
	OFHTTPServer *_server;
	OFTimer *_timer;
	enum {
		AWAITING_PROLOG,
		PARSING_HEADERS,
		SEND_RESPONSE
	} _state;
	uint8_t _HTTPMinorVersion;
	of_http_request_method_t _method;
	OFString *_host, *_path;
	uint16_t _port;
	OFMutableDictionary *_headers;
	size_t _contentLength;
	OFStream *_requestBody;
}

- (instancetype)initWithSocket: (OFTCPSocket *)sock
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
			server: (OFHTTPServer *)server;
- (bool)socket: (OFTCPSocket *)sock
- (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>
{
	OFTCPSocket *_socket;
	OF_KINDOF(OFTCPSocket *) _socket;
	uintmax_t _toRead;
	bool _atEndOfStream;
}

- (instancetype)initWithSocket: (OFTCPSocket *)sock
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
		 contentLength: (uintmax_t)contentLength;
@end

static const char *
statusCodeToString(short code)
{
	switch (code) {
227
228
229
230
231
232
233
234

235
236
237
238
239
240
241
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243







-
+







	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: true];
}

@implementation OFHTTPServerResponse
- (instancetype)initWithSocket: (OFTCPSocket *)sock
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
			server: (OFHTTPServer *)server
		       request: (OFHTTPRequest *)request
{
	self = [super init];

	_statusCode = 500;
	_socket = [sock retain];
364
365
366
367
368
369
370
371

372
373
374
375
376
377
378
366
367
368
369
370
371
372

373
374
375
376
377
378
379
380







-
+







		return -1;

	return [_socket fileDescriptorForWriting];
}
@end

@implementation OFHTTPServer_Connection
- (instancetype)initWithSocket: (OFTCPSocket *)sock
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
			server: (OFHTTPServer *)server
{
	self = [super init];

	@try {
		_socket = [sock retain];
		_server = [server retain];
403
404
405
406
407
408
409
410

411
412
413
414
415
416
417
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419







-
+







	[_path release];
	[_headers release];
	[_requestBody release];

	[super dealloc];
}

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

655
656
657
658
659
660
661
662
663


664
665
666
667
668
669
670
657
658
659
660
661
662
663


664
665
666
667
668
669
670
671
672







-
-
+
+







			  response: response];

	objc_autoreleasePoolPop(pool);
}
@end

@implementation OFHTTPServerRequestBodyStream
- (instancetype)initWithSocket: (OFTCPSocket *)sock
		     contentLength: (uintmax_t)contentLength
- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock
		 contentLength: (uintmax_t)contentLength
{
	self = [super init];

	@try {
		_socket = [sock retain];
		_toRead = contentLength;
	} @catch (id e) {
722
723
724
725
726
727
728
729





730
731
732
733
734
735
736
724
725
726
727
728
729
730

731
732
733
734
735
736
737
738
739
740
741
742







-
+
+
+
+
+







{
	[_socket release];
	_socket = nil;
}
@end

@implementation OFHTTPServer
@synthesize host = _host, port = _port, delegate = _delegate, name = _name;
@synthesize host = _host, port = _port, usesTLS = _usesTLS;
@synthesize certificateFile = _certificateFile;
@synthesize privateKeyFile = _privateKeyFile;
@synthesize privateKeyPassphrase = _privateKeyPassphrase, delegate = _delegate;
@synthesize name = _name;

+ (instancetype)server
{
	return [[[self alloc] init] autorelease];
}

- (instancetype)init
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
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
798
799
800
801
802


803
804
805
806
807
808
809
810
811







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


















-
-
+
+







{
	if (_host == nil)
		@throw [OFInvalidArgumentException exception];

	if (_listeningSocket != nil)
		@throw [OFAlreadyConnectedException exception];

	if (_usesTLS) {
		id <OFTLSSocket> listeningSocket;

		if (of_tls_socket_class == Nil)
			@throw [OFUnsupportedProtocolException exception];

		_listeningSocket = [[of_tls_socket_class alloc] init];

		listeningSocket = _listeningSocket;
		[listeningSocket setCertificateFile: _certificateFile];
		[listeningSocket setPrivateKeyFile: _privateKeyFile];
		[listeningSocket
		    setPrivateKeyPassphrase: _privateKeyPassphrase];
	} else
	_listeningSocket = [[OFTCPSocket alloc] init];
		_listeningSocket = [[OFTCPSocket alloc] init];

	_port = [_listeningSocket bindToHost: _host
					port: _port];
	[_listeningSocket listen];

	[_listeningSocket asyncAcceptWithTarget: self
				       selector: @selector(of_socket:
						     didAcceptSocket:context:
						     exception:)
					context: nil];
}

- (void)stop
{
	[_listeningSocket cancelAsyncRequests];
	[_listeningSocket release];
	_listeningSocket = nil;
}

- (bool)of_socket: (OFTCPSocket *)sock
  didAcceptSocket: (OFTCPSocket *)clientSocket
- (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: