/* * ObjWebServer * Copyright (C) 2018, 2019 Jonathan Schleifer <js@heap.zone> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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 "ConfigParser.h" @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 { self = [super init]; @try { OFXMLElement *config = [[OFXMLElement alloc] initWithFile: configPath]; @try { [self _parseConfig: config]; } @finally { [config release]; } } @catch (id e) { [self release]; @throw e; } 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]; for (OFXMLElement *element in elements) { OFString *path = [[element attributeForName: @"path"] stringValue]; OFString *prefix = [[element attributeForName: @"prefix"] stringValue]; if (path == nil || prefix == nil) [self _invalidConfig: @"<module/> has no path attribute"]; [modules addObject: element]; } [modules makeImmutable]; _modules = [modules copy]; } - (void)_invalidConfig: (OFString *)message { [of_stderr writeFormat: @"Error parsing config: %@", message]; [OFApplication terminateWithStatus: 1]; } @end