/* * Copyright (c) 2008-2023 Jonathan Schleifer <js@nil.im> * * 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 * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <inttypes.h> #include <string.h> #import "TestsAppDelegate.h" static OFString *const module = @"OFHTTPClient"; static OFCondition *condition; static OFHTTPResponse *response = nil; @interface TestsAppDelegate (HTTPClientTests) <OFHTTPClientDelegate> @end @interface HTTPClientTestsServer: OFThread { @public uint16_t _port; } @end @implementation HTTPClientTestsServer - (id)main { OFTCPSocket *listener, *client; OFSocketAddress address; char buffer[5]; [condition lock]; listener = [OFTCPSocket socket]; address = [listener bindToHost: @"127.0.0.1" port: 0]; _port = OFSocketAddressIPPort(&address); [listener listen]; [condition signal]; [condition unlock]; client = [listener accept]; OFEnsure([[client readLine] isEqual: @"GET /foo HTTP/1.1"]); OFEnsure([[client readLine] hasPrefix: @"User-Agent:"]); OFEnsure([[client readLine] isEqual: @"Content-Length: 5"]); OFEnsure([[client readLine] isEqual: @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]); if (![[client readLine] isEqual: [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, _port]]) OFEnsure(0); OFEnsure([[client readLine] isEqual: @""]); [client readIntoBuffer: buffer exactLength: 5]; OFEnsure(memcmp(buffer, "Hello", 5) == 0); [client writeString: @"HTTP/1.0 200 OK\r\n" @"cONTeNT-lENgTH: 7\r\n" @"\r\n" @"foo\n" @"bar"]; [client close]; return nil; } @end @implementation TestsAppDelegate (OFHTTPClientTests) - (void)client: (OFHTTPClient *)client wantsRequestBody: (OFStream *)body request: (OFHTTPRequest *)request { [body writeString: @"Hello"]; } - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request response: (OFHTTPResponse *)response_ exception: (id)exception { OFEnsure(exception == nil); response = [response_ retain]; [[OFRunLoop mainRunLoop] stop]; } - (void)HTTPClientTests { void *pool = objc_autoreleasePoolPush(); HTTPClientTestsServer *server; OFIRI *IRI; OFHTTPClient *client; OFHTTPRequest *request; OFData *data; condition = [OFCondition condition]; [condition lock]; server = [[[HTTPClientTestsServer alloc] init] autorelease]; server.supportsSockets = true; [server start]; [condition wait]; [condition unlock]; IRI = [OFIRI IRIWithString: [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo", server->_port]]; TEST(@"-[asyncPerformRequest:]", (client = [OFHTTPClient client]) && (client.delegate = self) && (request = [OFHTTPRequest requestWithIRI: IRI]) && (request.headers = [OFDictionary dictionaryWithObject: @"5" forKey: @"Content-Length"]) && R([client asyncPerformRequest: request])) [[OFRunLoop mainRunLoop] runUntilDate: [OFDate dateWithTimeIntervalSinceNow: 2]]; [response autorelease]; TEST(@"Asynchronous handling of requests", response != nil) TEST(@"Normalization of server header keys", [response.headers objectForKey: @"Content-Length"] != nil) TEST(@"Correct parsing of data", (data = [response readDataUntilEndOfStream]) && data.count == 7 && memcmp(data.items, "foo\nbar", 7) == 0) [server join]; objc_autoreleasePoolPop(pool); } @end