Index: src/OFHTTPServer.h ================================================================== --- src/OFHTTPServer.h +++ src/OFHTTPServer.h @@ -91,13 +91,16 @@ */ @interface OFHTTPServer: OFObject { OFString *_Nullable _host; uint16_t _port; + bool _usesTLS; + OFString *_Nullable _certificateFile, *_Nullable _privateKeyFile; + const char *_Nullable _privateKeyPassphrase; id _Nullable _delegate; OFString *_Nullable _name; - OFTCPSocket *_Nullable _listeningSocket; + OF_KINDOF(OFTCPSocket *) _Nullable _listeningSocket; } /*! * @brief The host on which the HTTP server will listen. */ @@ -106,10 +109,34 @@ /*! * @brief The port on which the HTTP server will listen. */ @property (nonatomic) uint16_t port; +/*! + * @brief Whether the HTTP server uses TLS. + */ +@property (nonatomic) bool usesTLS; + +/*! + * @brief The path to the X.509 certificate file to use for TLS. + */ +@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile; + +/*! + * @brief The path to the PKCS#8 private key file to use for TLS. + */ +@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile; + +/*! + * @brief The passphrase to decrypt the PKCS#8 private key file for TLS. + * + * @warning You have to ensure that this is in secure memory protected from + * swapping! This is also the reason why this is not an OFString. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + const char *privateKeyPassphrase; + /*! * @brief The delegate for the HTTP server. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id delegate; Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -26,19 +26,21 @@ #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 @@ -47,33 +49,33 @@ * 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 { - 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, @@ -86,13 +88,13 @@ 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; @@ -100,16 +102,16 @@ - (void)createResponse; @end @interface OFHTTPServerRequestBodyStream: OFStream { - 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) @@ -229,11 +231,11 @@ 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]; @@ -366,11 +368,11 @@ return [_socket fileDescriptorForWriting]; } @end @implementation OFHTTPServer_Connection -- (instancetype)initWithSocket: (OFTCPSocket *)sock +- (instancetype)initWithSocket: (OF_KINDOF(OFTCPSocket *))sock server: (OFHTTPServer *)server { self = [super init]; @try { @@ -405,11 +407,11 @@ [_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) @@ -657,12 +659,12 @@ 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]; @@ -724,11 +726,15 @@ _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]; } @@ -758,11 +764,26 @@ @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; - _listeningSocket = [[OFTCPSocket alloc] init]; + if (_usesTLS) { + id 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]; + _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; [_listeningSocket asyncAcceptWithTarget: self @@ -777,12 +798,12 @@ [_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; Index: src/exceptions/OFUnsupportedProtocolException.h ================================================================== --- src/exceptions/OFUnsupportedProtocolException.h +++ src/exceptions/OFUnsupportedProtocolException.h @@ -37,22 +37,18 @@ /*! * @brief The URL whose protocol is unsupported. */ @property (readonly, nonatomic) OFURL *URL; -+ (instancetype)exception OF_UNAVAILABLE; - /*! * @brief Creates a new, autoreleased unsupported protocol exception. * * @param URL The URL whose protocol is unsupported * @return A new, autoreleased unsupported protocol exception */ + (instancetype)exceptionWithURL: (OFURL*)URL; -- (instancetype)init OF_UNAVAILABLE; - /*! * @brief Initializes an already allocated unsupported protocol exception * * @param URL The URL whose protocol is unsupported * @return An initialized unsupported protocol exception Index: src/exceptions/OFUnsupportedProtocolException.m ================================================================== --- src/exceptions/OFUnsupportedProtocolException.m +++ src/exceptions/OFUnsupportedProtocolException.m @@ -22,25 +22,15 @@ #import "OFURL.h" @implementation OFUnsupportedProtocolException @synthesize URL = _URL; -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)exceptionWithURL: (OFURL *)URL { return [[[self alloc] initWithURL: URL] autorelease]; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - - (instancetype)initWithURL: (OFURL *)URL { self = [super init]; _URL = [URL retain]; @@ -55,9 +45,12 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"The protocol of URL %@ is not supported!", _URL]; + if (_URL != nil) + return [OFString stringWithFormat: + @"The protocol of URL %@ is not supported!", _URL]; + else + return @"The requested protocol is unsupported!"; } @end