Overview
Comment: | Add support for TLS |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
441110b797fb685e64ebcd6e8321b29f |
User & Date: | js 2019-03-03 13:27:21 |
Context
2019-03-17
| ||
03:32 | Use dot syntax check-in: 58aa5e718e user: js tags: trunk | |
2019-03-03
| ||
13:27 | Add support for TLS check-in: 441110b797 user: js tags: trunk | |
12:52 | Enable multi-threading check-in: d69dfe4c1c user: js tags: trunk | |
Changes
Changes to .gitignore.
1 2 3 4 5 | *.o *~ ObjWebServer htdocs modules | > > | 1 2 3 4 5 6 7 | *.o *~ ObjWebServer htdocs localhost.crt localhost.key modules |
Changes to ConfigParser.h.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 | * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #import <ObjFW/ObjFW.h> @interface ConfigParser: OFObject { | > > > > > > > > > > > > | < | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #import <ObjFW/ObjFW.h> @interface ListenConfig: OFObject { OFString *_host; uint16_t _port; OFString *_TLSCertificateFile, *_TLSKeyFile; } @property (copy, nonatomic) OFString *host; @property (nonatomic) uint16_t port; @property (copy, nonatomic) OFString *TLSCertificateFile, *TLSKeyFile; @end @interface ConfigParser: OFObject { OFArray OF_GENERIC(ListenConfig *) *_listenConfigs; OFArray OF_GENERIC(OFXMLElement *) *_modules; } @property (readonly, nonatomic) OFArray OF_GENERIC(ListenConfig *) *listenConfigs; @property (readonly, nonatomic) OFArray OF_GENERIC(OFXMLElement *) *modules; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithConfigPath: (OFString *)configPath; @end |
Changes to ConfigParser.m.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 | @interface ConfigParser () - (void)_parseConfig: (OFXMLElement *)config; - (void)_parseListens: (OFArray OF_GENERIC(OFXMLElement *) *)elements; - (void)_parseModules: (OFArray OF_GENERIC(OFXMLElement *) *)elements; - (void)_invalidConfig: (OFString *)message; @end @implementation ConfigParser | > > > > > > > > > > > > > > > | | 20 21 22 23 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 | @interface ConfigParser () - (void)_parseConfig: (OFXMLElement *)config; - (void)_parseListens: (OFArray OF_GENERIC(OFXMLElement *) *)elements; - (void)_parseModules: (OFArray OF_GENERIC(OFXMLElement *) *)elements; - (void)_invalidConfig: (OFString *)message; @end @implementation ListenConfig @synthesize host = _host, port = _port; @synthesize TLSCertificateFile = _TLSCertificateFile; @synthesize TLSKeyFile = _TLSKeyFile; - (void)dealloc { [_host release]; [_TLSCertificateFile release]; [_TLSKeyFile release]; [super dealloc]; } @end @implementation ConfigParser @synthesize listenConfigs = _listenConfigs, modules = _modules; - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithConfigPath: (OFString *)configPath |
︙ | ︙ | |||
51 52 53 54 55 56 57 | } return self; } - (void)dealloc { | | | | > > | > > | | | > > > > > | > > > > > > | > > | > > > | | | 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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | } return self; } - (void)dealloc { [_listenConfigs release]; [super dealloc]; } - (void)_parseConfig: (OFXMLElement *)config { void *pool = objc_autoreleasePoolPush(); if ([config namespace] != nil || ![[config name] isEqual: @"ObjWebServer"]) [self _invalidConfig: @"Root element is not ObjWebServer"]; [self _parseListens: [config elementsForName: @"listen"]]; [self _parseModules: [config elementsForName: @"module"]]; objc_autoreleasePoolPop(pool); } - (void)_parseListens: (OFArray OF_GENERIC(OFXMLElement *) *)elements { OFMutableArray OF_GENERIC(ListenConfig *) *listenConfigs = [OFMutableArray array]; for (OFXMLElement *element in elements) { ListenConfig *listenConfig = [[[ListenConfig alloc] init] autorelease]; OFString *host = [[element attributeForName: @"host"] stringValue]; OFString *portString = [[element attributeForName: @"port"] stringValue]; OFXMLElement *TLS = [element elementForName: @"tls"]; if (host == nil) [self _invalidConfig: @"<listen/> is missing host attribute"]; if (portString == nil) [self _invalidConfig: @"<listen/> is missing port attribute"]; [listenConfig setHost: host]; @try { intmax_t port = [portString decimalValue]; if (port < 0 || port > 65535) @throw [OFInvalidFormatException exception]; [listenConfig setPort: port]; } @catch (OFInvalidFormatException *e) { [self _invalidConfig: @"<listen/> has invalid port"]; } if (TLS != nil) { OFString *certificateFile = [[TLS attributeForName: @"cert"] stringValue]; OFString *keyFile = [[TLS attributeForName: @"key"] stringValue]; if (certificateFile == nil) [self _invalidConfig: @"<tls/> has no cert attribute"]; if (keyFile == nil) [self _invalidConfig: @"<tls/> has no key attribute"]; [listenConfig setTLSCertificateFile: certificateFile]; [listenConfig setTLSKeyFile: keyFile]; } [listenConfigs addObject: listenConfig]; } [listenConfigs makeImmutable]; _listenConfigs = [listenConfigs copy]; } - (void)_parseModules: (OFArray OF_GENERIC(OFXMLElement *) *)elements { OFMutableArray OF_GENERIC(OFXMLElement *) *modules = [OFMutableArray array]; |
︙ | ︙ |
Changes to Makefile.
1 | all: | | | | 1 2 3 4 5 6 7 8 9 10 | all: @objfw-compile -Werror --package ObjOpenSSL -o ObjWebServer \ ConfigParser.m \ ObjWebServer.m @mkdir -p modules @objfw-compile --plugin -o modules/static StaticModule.m clean: rm -fr modules rm -f ObjWebServer *.o *~ |
Changes to ObjWebServer.m.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ConfigParser *_config; OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFPlugin <Module> *) *) *_modules; } - (OFPlugin <Module> *)loadModuleAtPath: (OFString *)path withConfig: (OFXMLElement *)config; | | < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ConfigParser *_config; OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFPlugin <Module> *) *) *_modules; } - (OFPlugin <Module> *)loadModuleAtPath: (OFString *)path withConfig: (OFXMLElement *)config; - (void)startWebserverWithListenConfig: (ListenConfig *)listenConfig; @end OF_APPLICATION_DELEGATE(ObjWebServer) @implementation ObjWebServer - (void)applicationDidFinishLaunching { |
︙ | ︙ | |||
58 59 60 61 62 63 64 | [modules addObject: [OFPair pairWithFirstObject: prefix secondObject: module]]; } [modules makeImmutable]; _modules = [modules copy]; | < | < < < | < < | < | | > > > | > > > > > | > > > > > > > > > | 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 120 121 122 123 124 125 126 127 | [modules addObject: [OFPair pairWithFirstObject: prefix secondObject: module]]; } [modules makeImmutable]; _modules = [modules copy]; for (ListenConfig *listenConfig in [_config listenConfigs]) [self startWebserverWithListenConfig: listenConfig]; } - (OFPlugin <Module> *)loadModuleAtPath: (OFString *)path withConfig: (OFXMLElement *)config { OFPlugin <Module> *module; of_log(@"Loading module at %@", path); module = [OFPlugin pluginFromFile: path]; [module parseConfig: config]; return module; } - (void)startWebserverWithListenConfig: (ListenConfig *)listenConfig { OFHTTPServer *server = [OFHTTPServer server]; [server setHost: [listenConfig host]]; [server setPort: [listenConfig port]]; if ([listenConfig TLSCertificateFile] != nil && [listenConfig TLSKeyFile] != nil) { [server setUsesTLS: true]; [server setCertificateFile: [listenConfig TLSCertificateFile]]; [server setPrivateKeyFile: [listenConfig TLSKeyFile]]; } [server setNumberOfThreads: [OFSystemInfo numberOfCPUs] + 1]; [server setDelegate: self]; of_log(@"Starting server on host %@ port %" PRIu16, [listenConfig host], [listenConfig port]); [server start]; } - (void)server: (OFHTTPServer *)server didReceiveRequest: (OFHTTPRequest *)request requestBody: (OFStream *)requestBody response: (OFHTTPResponse *)response { OFString *path = [[request URL] path]; of_log(@"Request: %@", request); for (OFPair OF_GENERIC(OFString *, id <Module>) *module in _modules) if ([path hasPrefix: [module firstObject]]) if ([[module secondObject] handleRequest: request requestBody: requestBody response: response]) return; } - (bool)server: (OFHTTPServer *)server didReceiveExceptionOnListeningSocket: (id)exception { of_log(@"Exception on listening socket: %@", exception); return true; } @end |
Changes to ObjWebServer.xml.
1 | <ObjWebServer> | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <ObjWebServer> <listen host='127.0.0.1' port='1234'> <tls cert='localhost.crt' key='localhost.key'/> </listen> <!--listen host='::1' port='1234'> <tls cert='localhost.crt' key='localhost.key'/> </listen--> <module prefix='/' path='modules/static'> <root>htdocs</root> <mime-type extension='' type='application/octet-stream'/> <mime-type extension='c' type='text/plain; encoding-UTF-8'/> <mime-type extension='cc' type='text/plain; encoding=UTF-8'/> <mime-type extension='css' type='text/css; encoding=UTF-8'/> <mime-type extension='gz' type='application/gzip'/> |
︙ | ︙ |