ObjWebServer  ObjWebServer.m at tip

File ObjWebServer.m from the latest check-in


/*
 * 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/>.
 */

#include <inttypes.h>

#import <ObjFW/ObjFW.h>

#import "ConfigParser.h"
#import "Module.h"

@interface ObjWebServer: OFObject <OFApplicationDelegate, OFHTTPServerDelegate>
{
	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
{
	OFMutableArray OF_GENERIC(OFPair OF_GENERIC(OFString *,
	    OFPlugin <Module> *) *) *modules;

	_config = [[ConfigParser alloc]
	    initWithConfigPath: @"ObjWebServer.xml"];

	modules = [OFMutableArray array];
	for (OFXMLElement *config in [_config modules]) {
		OFString *path =
		    [config attributeForName: @"path"].stringValue;
		OFString *prefix =
		    [config attributeForName: @"prefix"].stringValue;
		OFPlugin <Module> *module = [self loadModuleAtPath: path
							withConfig: config];

		[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;

	OFLog(@"Loading module at %@", path);

	module = [OFPlugin pluginWithPath: path];
	[module parseConfig: config];

	return module;
}

- (void)startWebserverWithListenConfig: (ListenConfig *)listenConfig
{
	OFHTTPServer *server = [OFHTTPServer server];
	server.host = listenConfig.host;
	server.port = listenConfig.port;

	if (listenConfig.TLSCertificateFile != nil &&
	    listenConfig.TLSKeyFile != nil) {
		server.usesTLS = true;
		server.certificateFile = listenConfig.TLSCertificateFile;
		server.privateKeyFile = listenConfig.TLSKeyFile;
	}

	server.numberOfThreads = [OFSystemInfo numberOfCPUs] + 1;
	server.delegate = self;

	OFLog(@"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;

	OFLog(@"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
{
	OFLog(@"Exception on listening socket: %@", exception);

	return true;
}
@end