@@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2021 Jonathan Schleifer + * Copyright (c) 2008-2022 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -13,10 +13,11 @@ * file. */ #include "config.h" +#include #include #include #import "OFHTTPServer.h" #import "OFArray.h" @@ -26,11 +27,10 @@ #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" #import "OFNumber.h" #import "OFSocket+Private.h" #import "OFTCPSocket.h" -#import "OFTLSSocket.h" #import "OFThread.h" #import "OFTimer.h" #import "OFURL.h" #import "OFAlreadyConnectedException.h" @@ -114,16 +114,17 @@ @interface OFHTTPServerThread: OFThread - (void)stop; @end #endif -static OF_INLINE OFString * +static OFString * normalizedKey(OFString *key) { char *cString = OFStrDup(key.UTF8String); unsigned char *tmp = (unsigned char *)cString; bool firstLetter = true; + OFString *ret; while (*tmp != '\0') { if (!OFASCIIIsAlpha(*tmp)) { firstLetter = true; tmp++; @@ -136,16 +137,18 @@ firstLetter = false; tmp++; } @try { - return [OFString stringWithUTF8StringNoCopy: cString - freeWhenDone: true]; + ret = [OFString stringWithUTF8StringNoCopy: cString + freeWhenDone: true]; } @catch (id e) { OFFreeMemory(cString); @throw e; } + + return ret; } @implementation OFHTTPServerResponse - (instancetype)initWithSocket: (OFStreamSocket *)sock server: (OFHTTPServer *)server @@ -223,12 +226,22 @@ @throw [OFNotOpenException exceptionWithObject: self]; if (!_headersSent) [self of_sendHeaders]; - if (!_chunked) - return [_socket writeBuffer: buffer length: length]; + if (!_chunked) { + @try { + [_socket writeBuffer: buffer length: length]; + } @catch (OFWriteFailedException *e) { + if (e.errNo == EWOULDBLOCK || e.errNo == EAGAIN) + return e.bytesWritten; + + @throw e; + } + + return length; + } pool = objc_autoreleasePoolPush(); [_socket writeString: [OFString stringWithFormat: @"%zX\r\n", length]]; objc_autoreleasePoolPop(pool); @@ -523,20 +536,27 @@ URL.scheme = @"http"; URL.host = _host; if (_port != 80) URL.port = [OFNumber numberWithUnsignedShort: _port]; - if ((pos = [_path rangeOfString: @"?"].location) != OFNotFound) { - OFString *path, *query; - - path = [_path substringToIndex: pos]; - query = [_path substringFromIndex: pos + 1]; - - URL.URLEncodedPath = path; - URL.URLEncodedQuery = query; - } else - URL.URLEncodedPath = _path; + @try { + if ((pos = [_path rangeOfString: @"?"].location) != + OFNotFound) { + OFString *path, *query; + + path = [_path substringToIndex: pos]; + query = [_path substringFromIndex: pos + 1]; + + URL.URLEncodedPath = path; + URL.URLEncodedQuery = query; + } else + URL.URLEncodedPath = _path; + } @catch (OFInvalidFormatException *e) { + objc_autoreleasePoolPop(pool); + [self sendErrorAndClose: 400]; + return; + } [URL makeImmutable]; request = [OFHTTPRequest requestWithURL: URL]; request.method = _method; @@ -806,70 +826,10 @@ - (uint16_t)port { return _port; } -- (void)setUsesTLS: (bool)usesTLS -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _usesTLS = usesTLS; -} - -- (bool)usesTLS -{ - return _usesTLS; -} - -- (void)setCertificateFile: (OFString *)certificateFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _certificateFile; - _certificateFile = [certificateFile copy]; - [old release]; -} - -- (OFString *)certificateFile -{ - return _certificateFile; -} - -- (void)setPrivateKeyFile: (OFString *)privateKeyFile -{ - OFString *old; - - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - old = _privateKeyFile; - _privateKeyFile = [privateKeyFile copy]; - [old release]; -} - -- (OFString *)privateKeyFile -{ - return _privateKeyFile; -} - -- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase -{ - if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; - - _privateKeyPassphrase = privateKeyPassphrase; -} - -- (const char *)privateKeyPassphrase -{ - return _privateKeyPassphrase; -} - #ifdef OF_HAVE_THREADS - (void)setNumberOfThreads: (size_t)numberOfThreads { if (numberOfThreads == 0) @throw [OFInvalidArgumentException exception]; @@ -894,25 +854,11 @@ @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) @throw [OFAlreadyConnectedException exception]; - if (_usesTLS) { - OFTCPSocket *TLSSocket; - - if (OFTLSSocketClass == Nil) - @throw [OFUnsupportedProtocolException exception]; - - TLSSocket = [[OFTLSSocketClass alloc] init]; - _listeningSocket = TLSSocket; - - TLSSocket.certificateFile = _certificateFile; - TLSSocket.privateKeyFile = _privateKeyFile; - TLSSocket.privateKeyPassphrase = _privateKeyPassphrase; - } else - _listeningSocket = [[OFTCPSocket alloc] init]; - + _listeningSocket = [[OFTCPSocket alloc] init]; _port = [_listeningSocket bindToHost: _host port: _port]; [_listeningSocket listen]; #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) {