ObjFW  Diff

Differences From Artifact [7e47217e14]:

To Artifact [a4708f3429]:


137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160

161
162
163
164
165

166
167
168
169
170
171
172

173
174
175
176
177
178
179
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159

160
161
162
163
164

165
166
167
168
169
170
171

172
173
174
175
176
177
178
179







-
+








-
+






-
+




-
+






-
+







}

static OF_INLINE OFString*
normalized_key(OFString *key)
{
	char *cString = strdup([key UTF8String]);
	uint8_t *tmp = (uint8_t*)cString;
	BOOL firstLetter = YES;
	bool firstLetter = true;

	if (cString == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithClass: nil
			 requestedSize: strlen([key UTF8String])];

	while (*tmp != '\0') {
		if (!isalnum(*tmp)) {
			firstLetter = YES;
			firstLetter = true;
			tmp++;
			continue;
		}

		*tmp = (firstLetter ? toupper(*tmp) : tolower(*tmp));

		firstLetter = NO;
		firstLetter = false;
		tmp++;
	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: YES];
				       freeWhenDone: true];
}

@interface OFHTTPServerReply: OFHTTPRequestReply
{
	OFTCPSocket *_socket;
	OFHTTPServer *_server;
	BOOL _chunked, _headersSent, _closed;
	bool _chunked, _headersSent, _closed;
}

- initWithSocket: (OFTCPSocket*)socket
	  server: (OFHTTPServer*)server;
@end

@implementation OFHTTPServerReply
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234
220
221
222
223
224
225
226

227
228
229
230
231
232
233
234







-
+







	while ((key = [keyEnumerator nextObject]) != nil &&
	    (value = [valueEnumerator nextObject]) != nil)
		if (![key isEqual: @"Server"] && ![key isEqual: @"Date"])
			[_socket writeFormat: @"%@: %@\r\n", key, value];

	[_socket writeString: @"\r\n"];

	_headersSent = YES;
	_headersSent = true;
	_chunked = [[_headers objectForKey: @"Transfer-Encoding"]
	    isEqual: @"chunked"];

	objc_autoreleasePoolPop(pool);
}

- (void)lowlevelWriteBuffer: (const void*)buffer
262
263
264
265
266
267
268
269

270
271
272
273
274
275
276
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276







-
+








	if (_chunked)
		[_socket writeBuffer: "0\r\n\r\n"
			      length: 5];

	[_socket close];

	_closed = YES;
	_closed = true;
}

- (int)fileDescriptorForWriting
{
	return [_socket fileDescriptorForWriting];
}
@end
292
293
294
295
296
297
298
299

300
301
302
303
304



305
306
307
308

309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

327
328
329
330
331
332
333
292
293
294
295
296
297
298

299
300
301



302
303
304
305
306
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

326
327
328
329
330
331
332
333







-
+


-
-
-
+
+
+



-
+

















-
+







	OFMutableDictionary *_headers;
	size_t _contentLength;
	OFDataArray *_POSTData;
}

- initWithSocket: (OFTCPSocket*)socket
	  server: (OFHTTPServer*)server;
- (BOOL)socket: (OFTCPSocket*)socket
- (bool)socket: (OFTCPSocket*)socket
   didReadLine: (OFString*)line
     exception: (OFException*)exception;
- (BOOL)parseProlog: (OFString*)line;
- (BOOL)parseHeaders: (OFString*)line;
-      (BOOL)socket: (OFTCPSocket*)socket
- (bool)parseProlog: (OFString*)line;
- (bool)parseHeaders: (OFString*)line;
-      (bool)socket: (OFTCPSocket*)socket
  didReadIntoBuffer: (const char*)buffer
	     length: (size_t)length
	  exception: (OFException*)exception;
- (BOOL)sendErrorAndClose: (short)statusCode;
- (bool)sendErrorAndClose: (short)statusCode;
- (void)createReply;
@end

@implementation OFHTTPServer_Connection
- initWithSocket: (OFTCPSocket*)socket
	  server: (OFHTTPServer*)server
{
	self = [super init];

	@try {
		_socket = [socket retain];
		_server = [server retain];
		_timer = [[OFTimer
		    scheduledTimerWithTimeInterval: 10
					    target: socket
					  selector: @selector(
							cancelAsyncRequests)
					   repeats: NO] retain];
					   repeats: false] retain];
		_state = AWAITING_PROLOG;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
345
346
347
348
349
350
351
352

353
354
355
356
357

358
359
360
361
362
363
364
365

366
367
368
369

370
371
372

373
374

375
376
377

378
379
380
381
382
383

384
385
386
387
388
389
390
345
346
347
348
349
350
351

352
353
354
355
356

357
358
359
360
361
362
363
364

365
366
367
368

369
370
371

372
373

374
375
376

377
378
379
380
381
382

383
384
385
386
387
388
389
390







-
+




-
+







-
+



-
+


-
+

-
+


-
+





-
+







	[_path release];
	[_headers release];
	[_POSTData release];

	[super dealloc];
}

- (BOOL)socket: (OFTCPSocket*)socket
- (bool)socket: (OFTCPSocket*)socket
   didReadLine: (OFString*)line
     exception: (OFException*)exception
{
	if (line == nil || exception != nil)
		return NO;
		return false;

	@try {
		switch (_state) {
		case AWAITING_PROLOG:
			return [self parseProlog: line];
		case PARSING_HEADERS:
			if (![self parseHeaders: line])
				return NO;
				return false;

			if (_state == SEND_REPLY) {
				[self createReply];
				return NO;
				return false;
			}

			return YES;
			return true;
		default:
			return NO;
			return false;
		}
	} @catch (OFWriteFailedException *e) {
		return NO;
		return false;
	}

	abort();
}

- (BOOL)parseProlog: (OFString*)line
- (bool)parseProlog: (OFString*)line
{
	OFString *type;
	size_t pos;

	@try {
		OFString *version = [line
		    substringWithRange: of_range([line length] - 9, 9)];
426
427
428
429
430
431
432
433

434
435
436

437
438
439
440
441
442
443
426
427
428
429
430
431
432

433
434
435

436
437
438
439
440
441
442
443







-
+


-
+








	if (![_path hasPrefix: @"/"])
		return [self sendErrorAndClose: 400];

	_headers = [[OFMutableDictionary alloc] init];
	_state = PARSING_HEADERS;

	return YES;
	return true;
}

- (BOOL)parseHeaders: (OFString*)line
- (bool)parseHeaders: (OFString*)line
{
	OFString *key, *value;
	size_t pos;

	if ([line length] == 0) {
		switch (_requestType) {
		case OF_HTTP_REQUEST_TYPE_GET:
466
467
468
469
470
471
472
473

474
475
476

477
478
479
480
481
482
483
466
467
468
469
470
471
472

473
474
475

476
477
478
479
480
481
482
483







-
+


-
+







					      target: self
					    selector: @selector(socket:
							  didReadIntoBuffer:
							  length:exception:)];
			[_timer setFireDate:
			    [OFDate dateWithTimeIntervalSinceNow: 5]];

			return NO;
			return false;
		}

		return YES;
		return true;
	}

	pos = [line rangeOfString: @":"].location;
	if (pos == OF_NOT_FOUND)
		return [self sendErrorAndClose: 400];

	key = [line substringWithRange: of_range(0, pos)];
516
517
518
519
520
521
522
523

524
525
526

527
528
529
530
531
532

533
534
535
536
537
538
539
540
541

542
543
544

545
546
547
548
549

550
551
552

553
554
555
556
557
558
559
560
561
562
563
564
565

566
567
568
569
570
571
572
516
517
518
519
520
521
522

523
524
525

526
527
528
529
530
531

532
533
534
535
536
537
538
539
540

541
542
543

544
545
546
547
548

549
550
551

552
553
554
555
556
557
558
559
560
561
562
563
564

565
566
567
568
569
570
571
572







-
+


-
+





-
+








-
+


-
+




-
+


-
+












-
+







		} else {
			[_host release];
			_host = [value retain];
			_port = 80;
		}
	}

	return YES;
	return true;
}

-      (BOOL)socket: (OFTCPSocket*)socket
-      (bool)socket: (OFTCPSocket*)socket
  didReadIntoBuffer: (const char*)buffer
	     length: (size_t)length
	  exception: (OFException*)exception
{
	if ([socket isAtEndOfStream] || exception != nil)
		return NO;
		return false;

	[_POSTData addItems: buffer
		      count: length];

	if ([_POSTData count] >= _contentLength) {
		@try {
			[self createReply];
		} @catch (OFWriteFailedException *e) {
			return NO;
			return false;
		}

		return NO;
		return false;
	}

	[_timer setFireDate: [OFDate dateWithTimeIntervalSinceNow: 5]];

	return YES;
	return true;
}

- (BOOL)sendErrorAndClose: (short)statusCode
- (bool)sendErrorAndClose: (short)statusCode
{
	OFString *date = [[OFDate date]
	    dateStringWithFormat: @"%a, %d %b %Y %H:%M:%S GMT"];

	[_socket writeFormat: @"HTTP/1.1 %d %s\r\n"
			      @"Date: %@\r\n"
			      @"Server: %@\r\n"
			      @"\r\n",
			      statusCode, status_code_to_string(statusCode),
			      date, [_server name]];
	[_socket close];

	return NO;
	return false;
}

- (void)createReply
{
	OFURL *URL;
	OFHTTPRequest *request;
	OFHTTPServerReply *reply;
645
646
647
648
649
650
651
652

653
654
655
656
657

658
659
660
661
662
663
664
645
646
647
648
649
650
651

652
653
654
655
656

657
658
659
660
661
662
663
664







-
+




-
+







	[_name release];

	[super dealloc];
}

- (void)setHost: (OFString*)host
{
	OF_SETTER(_host, host, YES, 1)
	OF_SETTER(_host, host, true, 1)
}

- (OFString*)host
{
	OF_GETTER(_host, YES)
	OF_GETTER(_host, true)
}

- (void)setPort: (uint16_t)port
{
	_port = port;
}

675
676
677
678
679
680
681
682

683
684
685
686
687

688
689
690
691
692
693
694
675
676
677
678
679
680
681

682
683
684
685
686

687
688
689
690
691
692
693
694







-
+




-
+







- (id <OFHTTPServerDelegate>)delegate
{
	return _delegate;
}

- (void)setName: (OFString*)name
{
	OF_SETTER(_name, name, YES, 1)
	OF_SETTER(_name, name, true, 1)
}

- (OFString*)name
{
	OF_GETTER(_name, YES)
	OF_GETTER(_name, true)
}

- (void)start
{
	if (_host == nil || _port == 0)
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
713
714
715
716
717
718
719
720

721
722
723
724
725
726
727
728
729
730
731
732

733
734
735
736
737
738
739
740
741
742
743

744
745
713
714
715
716
717
718
719

720
721
722
723
724
725
726
727
728
729
730
731

732
733
734
735
736
737
738
739
740
741
742

743
744
745







-
+











-
+










-
+


- (void)stop
{
	[_listeningSocket cancelAsyncRequests];
	[_listeningSocket release];
	_listeningSocket = nil;
}

- (BOOL)OF_socket: (OFTCPSocket*)socket
- (bool)OF_socket: (OFTCPSocket*)socket
  didAcceptSocket: (OFTCPSocket*)clientSocket
	exception: (OFException*)exception
{
	OFHTTPServer_Connection *connection;

	if (exception != nil) {
		if ([_delegate respondsToSelector:
		    @selector(server:didReceiveExceptionOnListeningSocket:)])
			return [_delegate		  server: self
			    didReceiveExceptionOnListeningSocket: exception];

		return NO;
		return false;
	}

	connection = [[[OFHTTPServer_Connection alloc]
	    initWithSocket: clientSocket
		    server: self] autorelease];

	[clientSocket asyncReadLineWithTarget: connection
				     selector: @selector(socket:didReadLine:
						  exception:)];

	return YES;
	return true;
}
@end