/ src / HTTP / CFHTTPServer.c
CFHTTPServer.c
   1  /*
   2   * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
   3   *
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   * 
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  /*
  24   *  CFHTTPServer.c
  25   *  CFNetwork
  26   *
  27   *  Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
  28   *
  29   */
  30  
  31  
  32  #pragma mark Description
  33  /*
  34      The http server is comprised of two objects: a HttpServer and a HttpConnection.  The
  35      HttpServer is primarily responsible for listening and accepting new connections.
  36      As individual connections are established, HttpConnections are created in order to
  37      maintain that single connection's instance.  The HttpServer then maintains the list
  38      of these HttpConnection's.
  39      
  40      Individual requests and responses are handled on a per-HttpConnection basis.  Although
  41      handled on individual HttpConnection's, clients adding responses for a given request
  42      do so through the HttpServer's interface.  The HttpServer will then pair the response
  43      to the request on the proper HttpConnection instance.
  44      
  45      All responses are sent out in the order in which the requests were received.  A set
  46      of responses can be held up should a response not be available for the head queued
  47      item.  This can take place since responses are not required to be queued at the
  48      moment that a request is received.
  49      
  50      When the response is added to the queue, two items are used.  First there is the
  51      queue of ordered requests on the connection.  This ordered array is maintained in
  52      order to send the responses in the correct order.  The second part is a dictionary
  53      mapping an individual request to its response.  A response is comprised of a set of
  54      headers (CFHTTPMessageRef) and a stream (CFReadStreamRef) which acts as the body.
  55      Every outgoing response has both of these elements.  This means that
  56      _CFHTTPServerAddResponse creates a stream for the body of the response and then calls
  57      _CFHTTPServerAddStreamedResponse.
  58      
  59      Some cheap object model:
  60      
  61      ------------  maintains  ---------------- receives  ---------
  62      |HttpServer|------------@|HttpConnection|----------@|request|
  63      ------------             ----------------           ---------
  64                                       |                     |
  65                                       @ vends               |
  66                                   ----------                |
  67                                   |response|-----------------
  68                                   ----------
  69  */
  70  
  71  #pragma mark -
  72  #pragma mark Includes
  73  #include "CFServerPriv.h"
  74  #include "CFHTTPServerPriv.h"
  75  #include "CFNetworkInternal.h"
  76  
  77  #include "CFRuntime.h"
  78  #if !defined(__WIN32__)
  79  #include <sys/types.h>
  80  #ifdef APPORTABLE
  81  #if !defined(MAX)
  82      #define MAX(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
  83  #endif
  84  #include <netinet/in.h>
  85  #endif
  86  #include <sys/socket.h>
  87  #else
  88  #include <winsock2.h>
  89  #define SOCK_MAXADDRLEN 255
  90  #endif
  91  
  92  
  93  #if 0
  94  #pragma mark -
  95  #pragma mark Constant Strings
  96  #endif
  97  
  98  #ifdef __CONSTANT_CFSTRINGS__
  99  #define _kCFHTTPServerDescribeFormat			CFSTR("<HttpServer 0x%x>{server=%@, connections=%@, info=%@}")
 100  #define _kCFHTTPServerPtrFormat					CFSTR("<0x%x>")
 101  #define _kCFHTTPServerContentLengthHeader		CFSTR("Content-length")
 102  #define _kCFHTTPServerContentLengthFormat		CFSTR("%d")
 103  #define _kCFHTTPServerConnectionDescribeFormat	CFSTR("<_HttpConnection 0x%x>{server=0x%x, timer=%@, inStream=%@, outStream=%@, responses=%@, requests=%@, buffered=%@}")
 104  #define _kCFHTTPServerTransferEncodingHeader	CFSTR("Transfer-Encoding")
 105  #define _kCFHTTPServerTransferEncodingChunked	CFSTR("chunked")
 106  #define _kCFHTTPServerConnectionHeader			CFSTR("Connection")
 107  #define _kCFHTTPServerConnectionClose			CFSTR("close")
 108  #else
 109  static CONST_STRING_DECL(_kCFHTTPServerDescribeFormat, "<HttpServer 0x%x>{server=%@, connections=%@, info=%@}")
 110  static CONST_STRING_DECL(_kCFHTTPServerPtrFormat, "<0x%x>")
 111  static CONST_STRING_DECL(_kCFHTTPServerContentLengthHeader, "Content-length")
 112  static CONST_STRING_DECL(_kCFHTTPServerContentLengthFormat, "%d")
 113  static CONST_STRING_DECL(_kCFHTTPServerConnectionDescribeFormat, "<_HttpConnection 0x%x>{server=0x%x, timer=%@, inStream=%@, outStream=%@, responses=%@, requests=%@, buffered=%@}")
 114  static CONST_STRING_DECL(_kCFHTTPServerTransferEncodingHeader, "Transfer-Encoding")
 115  static CONST_STRING_DECL(_kCFHTTPServerTransferEncodingChunked, "chunked")
 116  static CONST_STRING_DECL(_kCFHTTPServerConnectionHeader, "Connection")
 117  static CONST_STRING_DECL(_kCFHTTPServerConnectionClose, "close")
 118  #endif	/* __CONSTANT_CFSTRINGS__ */
 119  
 120  
 121  #pragma mark -
 122  #pragma mark Type Declarations
 123  
 124  typedef struct {
 125      CFRuntimeBase			_base;			// CFRuntimeBase for CF types
 126  	
 127  	_CFServerRef			_server;		// Underlying server object.
 128  	
 129  	CFMutableArrayRef		_connections;	// All outstanding HttpConnection's
 130      
 131      _CFHTTPServerCallBacks	_callbacks;		// Callback functions for user
 132      _CFHTTPServerContext	_ctxt;			// User's context for callback
 133  } HttpServer;
 134  
 135  
 136  typedef struct {
 137      CFAllocatorRef			_alloc;			// Allocator used to allocate this
 138      UInt32					_rc;			// Number of times retained.
 139  	
 140  	HttpServer*				_server;		// Reference back to the owning server context.
 141  	
 142      CFDataRef				_peer;			// Peer's address
 143      
 144      CFRunLoopTimerRef		_timer;			// Timer for controlling timeouts
 145      
 146      CFReadStreamRef			_inStream;		// Incoming data stream
 147      CFWriteStreamRef		_outStream;		// Outgoing data stream
 148  	
 149  	CFMutableDictionaryRef	_responses;		// Responses keyed by their requests
 150  	CFMutableArrayRef		_requests;		// Ordered incoming requests
 151  	
 152  	CFMutableDataRef		_bufferedBytes;	// Bytes bound for delivery but not yet sent
 153  } HttpConnection;
 154  
 155  
 156  #pragma mark -
 157  #pragma mark Static Function Declarations
 158  
 159  // Functions for HttpServer object
 160  static void _HttpServerRelease(_CFHTTPServerRef server);
 161  static CFStringRef _HttpServerCopyDescription(_CFHTTPServerRef server);
 162  
 163  // Functions for HttpConnection object
 164  static HttpConnection* _HttpConnectionCreate(CFAllocatorRef alloc, HttpServer* server, CFSocketNativeHandle s);
 165  static HttpConnection* _HttpConnectionRetain(HttpConnection* connection);
 166  static void _HttpConnectionRelease(HttpConnection* connection);
 167  static CFStringRef _HttpConnectionCopyDescription(HttpConnection* connection);
 168  
 169  // Handlers for HttpConnection object
 170  static void _HttpConnectionHandleRequest(HttpConnection* connection);
 171  static void _HttpConnectionHandleHasBytesAvailable(HttpConnection* connection);
 172  static void _HttpConnectionHandleCanAcceptBytes(HttpConnection* connection);
 173  static void _HttpConnectionHandleErrorOccurred(HttpConnection* connection, const CFStreamError* error);
 174  static void _HttpConnectionHandleTimeOut(HttpConnection* connection);
 175  
 176  static const void*	_ArrayRetainCallBack(CFAllocatorRef allocator, const HttpConnection* connection);
 177  static void _ArrayReleaseCallBack(CFAllocatorRef allocator, const HttpConnection* connection);
 178  
 179  
 180  // CFType callbacks -- call into HttpConnection's handlers
 181  static void _ReadStreamCallBack(CFReadStreamRef inStream, CFStreamEventType type, HttpConnection* connection);
 182  static void _WriteStreamCallBack(CFWriteStreamRef outStream, CFStreamEventType type, HttpConnection* connection);
 183  static void _TimerCallBack(CFRunLoopTimerRef timer, HttpConnection* connection);
 184  
 185  // Functions for manipulating HttpServer's array of HttpConnection's
 186  static void _HttpServerAddConnection(HttpServer* server, HttpConnection* connection);
 187  static void _HttpServerRemoveConnection(HttpServer* server, HttpConnection* connection);
 188  
 189  // Handlers for HttpServer object
 190  static void _HttpServerHandleNewConnection(HttpServer* server, CFSocketNativeHandle sock);
 191  static void _HttpServerHandleError(HttpServer* server, const CFStreamError* error);
 192  
 193  // Server callback -- call into HttpServer's handlers
 194  static void _ServerCallBack(_CFServerRef server, CFSocketNativeHandle sock, const CFStreamError* error, HttpServer* httpServer);
 195  
 196  // General use function
 197  static CFNumberRef _CFNumberCreateWithString(CFAllocatorRef allocator, CFStringRef string);
 198  
 199  
 200  #if 0
 201  #pragma mark -
 202  #pragma mark Extern Function Declarations
 203  #endif
 204  
 205  extern void _CFSocketStreamCreatePair(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFSocketNativeHandle s,
 206  									  const CFSocketSignature* sig, CFReadStreamRef* readStream, CFWriteStreamRef* writeStream);
 207  
 208  
 209  
 210  
 211  #pragma mark -
 212  #pragma mark Static Variable Definitions
 213  
 214  // A shorter timeout should be used for a more heavily used server.
 215  #define kTimeOutInSeconds ((CFTimeInterval)60.0)
 216  #define kBufferSize ((CFIndex)8192)
 217  
 218  #define kReadEvents	((CFOptionFlags)(kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred))
 219  #define kWriteEvents	((CFOptionFlags)(kCFStreamEventCanAcceptBytes | kCFStreamEventErrorOccurred))
 220  
 221  static CFTypeID _HttpServerTypeId = _kCFRuntimeNotATypeID;
 222  
 223  
 224  #pragma mark -
 225  #pragma mark Extern Function Definitions (API)
 226  
 227  
 228  /* CF_EXPORT */ CFTypeID
 229  _CFHTTPServerGetTypeID(void) {
 230      
 231      if (_HttpServerTypeId == _kCFRuntimeNotATypeID) {
 232  
 233          static const CFRuntimeClass HttpServerClass = {
 234              0,														// version
 235              "_CFHTTPServer",										// class name
 236              NULL,													// init
 237              NULL,													// copy
 238              (void(*)(CFTypeRef))_HttpServerRelease,					// finalize
 239              NULL,													// equal
 240              NULL,													// hash
 241              NULL,													// copy formatting description
 242              
 243              (CFStringRef(*)(CFTypeRef))_HttpServerCopyDescription	// copy debug description
 244          };
 245          
 246          _HttpServerTypeId = _CFRuntimeRegisterClass(&HttpServerClass);
 247      }
 248          
 249      return _HttpServerTypeId;
 250  }
 251  
 252  
 253  /* CF_EXPORT */ _CFHTTPServerRef
 254  _CFHTTPServerCreate(CFAllocatorRef alloc, const _CFHTTPServerCallBacks* callbacks, _CFHTTPServerContext* context) {
 255  
 256      HttpServer* server = NULL;
 257  
 258      do {
 259  		_CFServerContext ctxt = {
 260              0,
 261              NULL,
 262              (CFAllocatorRetainCallBack)CFRetain,
 263              (CFAllocatorReleaseCallBack)CFRelease,
 264              (CFAllocatorCopyDescriptionCallBack)CFCopyDescription
 265          };
 266          
 267  		CFArrayCallBacks arrayCallBacks = {
 268              0,
 269              (CFArrayRetainCallBack)_ArrayRetainCallBack,
 270              (CFArrayReleaseCallBack)_ArrayReleaseCallBack,
 271              (CFArrayCopyDescriptionCallBack)_HttpConnectionCopyDescription,
 272              NULL																// Default pointer comparison
 273          };
 274          
 275          CFTypeID id = _CFHTTPServerGetTypeID();
 276      
 277          // Ask CF to allocate the instance and then return it.
 278          if (id != _kCFRuntimeNotATypeID) {
 279              server = (HttpServer*)_CFRuntimeCreateInstance(alloc,
 280                                                             id,
 281                                                             sizeof(HttpServer) - sizeof(CFRuntimeBase),
 282                                                             NULL);
 283          }
 284          
 285          // Fail if unable to create the server
 286          if (server == NULL)
 287                  break;
 288  	
 289          server->_server = NULL;
 290  	    server->_connections = NULL;
 291          memset(&server->_callbacks, 0, sizeof(server->_callbacks));
 292          memset(&server->_ctxt, 0, sizeof(server->_ctxt));
 293          
 294  		// Set the info on the callback context
 295  		ctxt.info = server;
 296  		
 297  		// Create the server
 298  		server->_server = _CFServerCreate(alloc, (_CFServerCallBack)_ServerCallBack, &ctxt);
 299  
 300          // Require server in order to create.
 301          if (server->_server == NULL)
 302              break;
 303  			
 304  		server->_connections = CFArrayCreateMutable(alloc, 0, &arrayCallBacks);
 305  		
 306  		// Require the list of outstanding Http connections
 307  		if (server->_connections == NULL)
 308  			break;
 309                  
 310  		// Save the user's callbacks and context.
 311          memcpy(&(server->_callbacks), callbacks, sizeof(server->_callbacks));
 312  		memcpy(&(server->_ctxt), context, sizeof(server->_ctxt));
 313  		
 314  		// If there is info and a retain function, retain the info.
 315  		if (server->_ctxt.info && server->_ctxt.retain)
 316  			server->_ctxt.info = (void *)(server->_ctxt.retain(server->_ctxt.info));
 317  
 318          return (_CFHTTPServerRef)server;
 319              
 320      } while (0);
 321  	
 322  	// Something failed, so clean up.
 323  	if (server) {
 324  		_CFHTTPServerInvalidate((_CFHTTPServerRef)server);
 325  		CFRelease((_CFHTTPServerRef)server);
 326  	}
 327      
 328      return NULL;
 329  }
 330  
 331  
 332  /* static */ void
 333  _HttpServerRelease(_CFHTTPServerRef server) {
 334      
 335      // Invalidate the server which will release server and outstanding connections.
 336      _CFHTTPServerInvalidate(server);
 337  }
 338  
 339  
 340  /* static */ CFStringRef
 341  _HttpServerCopyDescription(_CFHTTPServerRef server) {
 342      
 343      CFStringRef info, result, serverDescription = NULL;
 344      HttpServer* s = (HttpServer*)server;
 345      CFAllocatorRef alloc = CFGetAllocator(server);
 346  	
 347      if (s->_server)
 348          serverDescription = CFCopyDescription(s->_server);
 349      
 350  	// Set the user's context based upon supplied "copyDescription"
 351  	if (s->_ctxt.copyDescription)
 352  		info = s->_ctxt.copyDescription(s->_ctxt.info);
 353  	else
 354  		info = CFStringCreateWithFormat(alloc, NULL, _kCFHTTPServerPtrFormat, (UInt32)(s->_ctxt.info));
 355      
 356  	// Create the debug string
 357      result = CFStringCreateWithFormat(alloc,
 358  									  NULL,
 359  									  _kCFHTTPServerDescribeFormat,
 360  									  (UInt32)s,
 361                                        serverDescription,
 362  									  s->_connections,
 363  									  info);
 364                                        
 365      if (serverDescription)
 366          CFRelease(serverDescription);
 367          
 368      CFRelease(info);
 369      
 370      return result;
 371  }
 372  
 373  
 374  /* CF_EXPORT */ Boolean
 375  _CFHTTPServerStart(_CFHTTPServerRef server, CFStringRef name, CFStringRef type, UInt32 port) {
 376  
 377      HttpServer* s = (HttpServer*)server;
 378  
 379      // Nothing special needed for the HTTP server.
 380      
 381      return _CFServerStart(s->_server, name, type, port);
 382  }
 383  
 384  
 385  /* CF_EXPORT */ void
 386  _CFHTTPServerInvalidate(_CFHTTPServerRef server) {
 387  	
 388  	HttpServer* s = (HttpServer*)server;
 389  	
 390  	// Release the user's context info pointer.
 391  	if (s->_ctxt.info && s->_ctxt.release)
 392  		s->_ctxt.release(s->_ctxt.info);
 393  		
 394  	// Clear out the context, so nothing can be called.
 395  	memset(&(s->_ctxt), 0, sizeof(s->_ctxt));
 396  	
 397  	// Guarantee that there will be no user callbacks.
 398      memset(&s->_callbacks, 0, sizeof(s->_callbacks));
 399      
 400      // Close out any outstanding connections.
 401      if (s->_connections) {
 402          CFRelease(s->_connections);
 403          s->_connections = NULL;
 404      }
 405      
 406      // If the server has been created, invalidate it and delete it.
 407      if (s->_server) {
 408          _CFServerInvalidate(s->_server);
 409          CFRelease(s->_server);
 410          s->_server = NULL;
 411      }
 412  }
 413  
 414  
 415  /* CF_EXPORT */ UInt32
 416  _CFHTTPServerGetPort(_CFHTTPServerRef server) {
 417  
 418      return ((HttpServer*)server)->_server ? _CFServerGetPort(((HttpServer*)server)->_server) : 0;
 419  }
 420  
 421  
 422  /* CF_EXPORT */ CFDataRef
 423  _CFHTTPServerCopyPeerAddressForRequest(_CFHTTPServerRef server, CFHTTPMessageRef request) {
 424      
 425      CFIndex i, count;
 426      HttpServer* s = (HttpServer*)server;
 427      
 428      // Prepare to look for the given request in the connections
 429      count = CFArrayGetCount(s->_connections);
 430      
 431      // Start the search
 432      for (i = 0; i < count; i++) {
 433          
 434          // **FIXME** This is somewhat incestuous.  The server should not be reaching
 435          // into the connections.  There should really be a HttpConnection method for
 436          // adding a response.
 437          
 438          // Pull out the current connection
 439          HttpConnection* c = (HttpConnection*)CFArrayGetValueAtIndex(s->_connections, i);
 440          
 441          // Check to see if the connection knows of the request
 442          CFIndex j = CFArrayGetFirstIndexOfValue(c->_requests, CFRangeMake(0, CFArrayGetCount(c->_requests)), request);
 443          
 444          // Handle the response if it was found
 445          if (j != kCFNotFound) {
 446          
 447              // return the copy that was found
 448              return (c->_peer == NULL) ? NULL : CFDataCreateCopy(CFGetAllocator(server), c->_peer);
 449          }
 450      }
 451  
 452      return NULL;
 453  }
 454  
 455  
 456  /* CF_EXPORT */ void
 457  _CFHTTPServerAddResponse(_CFHTTPServerRef server, CFHTTPMessageRef request, CFHTTPMessageRef response) {
 458  
 459      CFDataRef body;
 460      UInt8* bytes;
 461      CFReadStreamRef stream;
 462      CFIndex length;
 463      CFStringRef contentLength;
 464      
 465      CFAllocatorRef alloc = CFGetAllocator(server);
 466      
 467      // Make a copy of the response
 468      response = CFHTTPMessageCreateCopy(alloc, response);
 469      
 470      // Get the body and its length
 471      body = CFHTTPMessageCopyBody(response);
 472      
 473      if (body == NULL)
 474          body = CFDataCreate(alloc, NULL, 0);
 475      
 476      length = CFDataGetLength(body);
 477      
 478      // Pull the body off the response since the stream will be used
 479      CFHTTPMessageSetBody(response, NULL);
 480      
 481      // Allocate the buffer for the body
 482      bytes = (UInt8*)CFAllocatorAllocate(alloc, length, 0);
 483      
 484      // Copy the body into the buffer for streaming
 485      memmove(bytes, CFDataGetBytePtr(body), length);
 486      
 487      // Don't need the body anymore
 488      CFRelease(body);
 489      
 490      // Create the stream for the body
 491      stream = CFReadStreamCreateWithBytesNoCopy(alloc, bytes, length, alloc);
 492      
 493      // Check to see if there is a content length header.
 494      contentLength = CFHTTPMessageCopyHeaderFieldValue(response, _kCFHTTPServerContentLengthHeader);
 495      
 496      // If not, add one.
 497      if (contentLength == NULL) {
 498  
 499          // Create the header value with the length
 500          contentLength = CFStringCreateWithFormat(alloc, NULL, _kCFHTTPServerContentLengthFormat, length);
 501          
 502          // Add the header
 503          CFHTTPMessageSetHeaderFieldValue(response, _kCFHTTPServerContentLengthHeader, contentLength);
 504      }
 505      CFRelease(contentLength);
 506      
 507      // Add the streamed response
 508      _CFHTTPServerAddStreamedResponse(server, request, response, stream);
 509      
 510      // No longer needed now that it's in the queue
 511      CFRelease(stream);
 512      CFRelease(response);
 513  }
 514  
 515  
 516  /* CF_EXPORT */ void
 517  _CFHTTPServerAddStreamedResponse(_CFHTTPServerRef server, CFHTTPMessageRef request, CFHTTPMessageRef response, CFReadStreamRef body) {
 518  
 519      CFArrayRef list;
 520      CFIndex i, count;
 521      
 522      HttpServer* s = (HttpServer*)server;
 523      CFAllocatorRef alloc = CFGetAllocator(server);
 524      
 525      // Things to be put into the response list for a request
 526      CFTypeRef objs[] = {NULL, body};
 527      
 528      // Create a copy 'cause it may need adjustment
 529      objs[0] = CFHTTPMessageCreateCopy(alloc, response);
 530      
 531      // Create the response list for the request
 532      list = CFArrayCreate(alloc, objs, sizeof(objs) / sizeof(objs[0]), &kCFTypeArrayCallBacks);
 533      
 534      // Prepare to look for the given request in the connections
 535      count = CFArrayGetCount(s->_connections);
 536      
 537      // Start the search
 538      for (i = 0; i < count; i++) {
 539          
 540          // **FIXME** This is somewhat incestuous.  The server should not be reaching
 541          // into the connections.  There should really be a HttpConnection method for
 542          // adding a response.
 543          
 544          // Pull out the current connection
 545          HttpConnection* c = (HttpConnection*)CFArrayGetValueAtIndex(s->_connections, i);
 546          
 547          // Check to see if the connection knows of the request
 548          CFIndex j = CFArrayGetFirstIndexOfValue(c->_requests, CFRangeMake(0, CFArrayGetCount(c->_requests)), request);
 549          
 550          // Handle the response if it was found
 551          if (j != kCFNotFound) {
 552              
 553              // Add the response list to the connection for the given request
 554              CFDictionaryAddValue(c->_responses, request, list);
 555          
 556              // If the request was the head of the request queue and the stream can send, pump it.
 557              if ((j == 0) && CFWriteStreamCanAcceptBytes(c->_outStream))
 558                  _HttpConnectionHandleCanAcceptBytes(c);
 559          
 560              // Everything has been handled
 561              break;
 562          }
 563      }
 564      
 565      // List has been handled, so it's not needed anymore.
 566      CFRelease(list);
 567      
 568      CFRelease(objs[0]);
 569  }
 570  
 571  
 572  #pragma mark -
 573  #pragma mark Static Function Definitions
 574  
 575  /* static */ HttpConnection*
 576  _HttpConnectionCreate(CFAllocatorRef alloc, HttpServer* server, CFSocketNativeHandle s) {
 577      
 578      HttpConnection* connection = NULL;
 579  	    
 580  	do {
 581          uint8_t name[SOCK_MAXADDRLEN];
 582          socklen_t namelen = sizeof(name);
 583  
 584          CFRunLoopRef rl = CFRunLoopGetCurrent();
 585          
 586          CFRunLoopTimerContext timerCtxt = {
 587              0,
 588              NULL,
 589              NULL,
 590              NULL,
 591              (CFStringRef (*)(const void*))_HttpConnectionCopyDescription
 592          };
 593          
 594          CFStreamClientContext streamCtxt = {
 595              0,
 596              NULL,
 597              NULL,
 598              NULL,
 599              (CFStringRef (*)(void*))_HttpConnectionCopyDescription
 600          };
 601          
 602  		// Allocate the buffer for the connection.
 603  		connection = CFAllocatorAllocate(alloc, sizeof(connection[0]), 0);
 604  		
 605  		// Fail if unable to create the connection
 606  		if (connection == NULL)
 607  			break;
 608  		
 609  		memset(connection, 0, sizeof(connection[0]));
 610  		
 611  		// Save the allocator for deallocating later.
 612  		connection->_alloc = alloc ? CFRetain(alloc) : NULL;
 613  		
 614          // Bump the retain count.
 615          _HttpConnectionRetain(connection);
 616          
 617  		// Make sure the server is saved for the callback.
 618  		connection->_server = (HttpServer*)CFRetain((_CFHTTPServerRef)server);
 619  		
 620          if (0 == getpeername(s, (struct sockaddr *)name, &namelen))
 621              connection->_peer = CFDataCreate(alloc, name, namelen);
 622          
 623          // Set the info pointer for the contexts to be the connection.
 624          timerCtxt.info = connection;
 625          streamCtxt.info = connection;
 626          
 627          // Create the timer for detecting dead connections
 628          connection->_timer = CFRunLoopTimerCreate(alloc,
 629                                                    CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds,
 630                                                    kTimeOutInSeconds,
 631                                                    0,
 632                                                    0,
 633                                                    (CFRunLoopTimerCallBack)_TimerCallBack,
 634                                                    &timerCtxt);
 635          
 636          // Make sure it succeeded
 637          if (connection->_timer == NULL)
 638              break;
 639              
 640          // Add the timer to the run loop
 641          CFRunLoopAddTimer(rl, connection->_timer, kCFRunLoopCommonModes);
 642          
 643          // Create a pair of streams for performing HTTP.
 644  		_CFSocketStreamCreatePair(alloc, NULL, 0, s, NULL, &(connection->_inStream), &(connection->_outStream));
 645          
 646          // Make sure both were created
 647          if ((connection->_inStream == NULL) || (connection->_outStream == NULL))
 648              break;
 649          
 650          // Relinquish the socket to the streams
 651          CFReadStreamSetProperty(connection->_inStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
 652          CFWriteStreamSetProperty(connection->_outStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
 653          
 654          // Set the client to for each of the streams and for the proper events.
 655          CFReadStreamSetClient(connection->_inStream, kReadEvents, (CFReadStreamClientCallBack)_ReadStreamCallBack, &streamCtxt);
 656          CFWriteStreamSetClient(connection->_outStream, kWriteEvents, (CFWriteStreamClientCallBack)_WriteStreamCallBack, &streamCtxt);
 657          
 658          // Schedule both on the run loop
 659          CFReadStreamScheduleWithRunLoop(connection->_inStream, rl, kCFRunLoopCommonModes);
 660          CFWriteStreamScheduleWithRunLoop(connection->_outStream, rl, kCFRunLoopCommonModes);
 661          
 662          // Open up the streams
 663          CFReadStreamOpen(connection->_inStream);
 664          CFWriteStreamOpen(connection->_outStream);
 665          
 666          // Create the dictionary mapping requests to responses
 667          connection->_responses = CFDictionaryCreateMutable(alloc,
 668                                                             0,
 669                                                             &kCFTypeDictionaryKeyCallBacks,
 670                                                             &kCFTypeDictionaryValueCallBacks);
 671          
 672          // Make sure it worked
 673          if (connection->_responses == NULL)
 674              break;
 675          
 676          // Create the list of all outstanding, incoming requests
 677          connection->_requests = CFArrayCreateMutable(alloc,
 678                                                       0,
 679                                                       &kCFTypeArrayCallBacks);
 680          
 681          // Make sure the list was created
 682          if (connection->_requests == NULL)
 683              break;
 684          
 685          // Create a buffer for any buffered bytes which will be sent out
 686          connection->_bufferedBytes = CFDataCreateMutable(alloc, 0);
 687          
 688          // Make sure there is a buffer
 689          if (connection->_bufferedBytes == NULL)
 690              break;
 691          
 692          // It's all good
 693  		return connection;
 694  			
 695  	} while (0);
 696  	
 697  	// Something failed, so clean up.
 698  	if (connection)
 699          _HttpConnectionRelease(connection);
 700  
 701      return NULL;
 702  }
 703  
 704  
 705  /* static */ HttpConnection*
 706  _HttpConnectionRetain(HttpConnection* connection) {
 707  	
 708  	// Bump the retain count.
 709  	connection->_rc++;
 710  		
 711  	return connection;
 712  }
 713  
 714  
 715  /* static */ void
 716  _HttpConnectionRelease(HttpConnection* connection) {
 717  	
 718  	// Decrease the retain count.
 719  	connection->_rc--;
 720  	
 721  	// Destroy the object if not being held.
 722  	if (connection->_rc == 0) {
 723  		
 724  		// Hold locally so deallocation can happen and then safely release.
 725  		CFAllocatorRef alloc = connection->_alloc;
 726  
 727          CFRunLoopRef runLoop = CFRunLoopGetCurrent();
 728  
 729          if (connection->_server)
 730              CFRelease((_CFHTTPServerRef)connection->_server);
 731          
 732          if (connection->_peer)
 733              CFRelease(connection->_peer);
 734          
 735          // Check if the read stream exists.
 736          if (connection->_inStream) {
 737              
 738              // Unschedule, close, and release it.
 739              CFReadStreamSetClient(connection->_inStream, 0, NULL, NULL);
 740              CFReadStreamUnscheduleFromRunLoop(connection->_inStream, runLoop, kCFRunLoopCommonModes);
 741              CFReadStreamClose(connection->_inStream);
 742              CFRelease(connection->_inStream);
 743          }
 744      
 745          // Check if the write stream exists.
 746          if (connection->_outStream) {
 747              
 748              // Unschedule, close, and release it.
 749              CFWriteStreamSetClient(connection->_outStream, 0, NULL, NULL);
 750              CFWriteStreamUnscheduleFromRunLoop(connection->_outStream, runLoop, kCFRunLoopCommonModes);
 751              CFWriteStreamClose(connection->_outStream);
 752              CFRelease(connection->_outStream);
 753          }
 754          
 755          // If the timer exists, toss it too.
 756          if (connection->_timer != NULL) {
 757              CFRunLoopRemoveTimer(runLoop, connection->_timer, kCFRunLoopCommonModes);
 758              CFRunLoopTimerInvalidate(connection->_timer);
 759              CFRelease(connection->_timer);
 760          }
 761          
 762          // Toss the dictionary of requests and responses
 763          if (connection->_responses)
 764              CFRelease(connection->_responses);
 765              
 766          // Toss the list of incoming requests
 767          if (connection->_requests)
 768              CFRelease(connection->_requests);
 769              
 770          // Toss the buffered bytes
 771          if (connection->_bufferedBytes)
 772              CFRelease(connection->_bufferedBytes);
 773          
 774  		// Free the memory in use by the connection.
 775  		CFAllocatorDeallocate(alloc, connection);
 776  		
 777  		// Release the allocator.
 778  		if (alloc)
 779  			CFRelease(alloc);
 780  	}
 781  }
 782  
 783  
 784  /* static */ CFStringRef
 785  _HttpConnectionCopyDescription(HttpConnection* connection) {
 786      
 787      CFStringRef result;
 788      
 789  	// Create the debug string
 790      result = CFStringCreateWithFormat(connection->_alloc,
 791  									  NULL,
 792  									  _kCFHTTPServerConnectionDescribeFormat,
 793  									  (UInt32)connection,
 794                                        (UInt32)connection->_server,
 795  									  connection->_timer,
 796  									  connection->_inStream,
 797                                        connection->_outStream,
 798                                        connection->_responses,
 799                                        connection->_requests,
 800                                        connection->_bufferedBytes);
 801                                        
 802      return result;
 803  }
 804  
 805  
 806  /* static */ void
 807  _HttpConnectionHandleRequest(HttpConnection* connection) {
 808      
 809      assert(0 != CFArrayGetCount(connection->_requests));
 810      
 811      // Get the message with which to work (the last one)
 812      CFHTTPMessageRef msg = (CFHTTPMessageRef)CFArrayGetValueAtIndex(connection->_requests,
 813                                                                      CFArrayGetCount(connection->_requests) - 1);
 814  
 815      while (msg) {
 816  
 817          // Use to see if it is a chunked request
 818          CFStringRef encoding = CFHTTPMessageCopyHeaderFieldValue(msg, _kCFHTTPServerTransferEncodingHeader);
 819  
 820          // Assume not chunked
 821          Boolean chunked = FALSE;
 822          
 823          // If there is encoding, cheaply check for chunked.
 824          if (encoding) {
 825              chunked = CFStringFindWithOptions(encoding,
 826                                                _kCFHTTPServerTransferEncodingChunked,
 827                                                CFRangeMake(0, CFStringGetLength(encoding)),
 828                                                kCFCompareCaseInsensitive,
 829                                                NULL);
 830              CFRelease(encoding);
 831          }
 832  
 833          // If it's chunked, bail 'cause the API just isn't ready for
 834          // these types of requests yet.
 835          if (chunked) {
 836  
 837              // Establish an error
 838              CFStreamError error = {kCFStreamErrorDomainHTTP, kCFStreamErrorHTTPParseFailure};
 839  
 840              // Handle it just like an error.
 841              _HttpConnectionHandleErrorOccurred(connection, &error);
 842  
 843              break;
 844          }
 845  
 846          // No chunking info so use size
 847          else {
 848  
 849              // Assume zero length to start.
 850              SInt32 size = 0;
 851  
 852              // Grab the body for testing
 853              CFDataRef body = CFHTTPMessageCopyBody(msg);
 854  
 855              // Get the length of the current body on the message
 856              CFIndex length = body ? CFDataGetLength(body) : 0;
 857              
 858              // Get the size to see if everything is there.
 859              CFStringRef value = CFHTTPMessageCopyHeaderFieldValue(msg, _kCFHTTPServerContentLengthHeader);
 860  
 861              // Need to convert the value if there was a header
 862              if (value) {
 863  
 864                  // Convert the header value to a CFNumber
 865                  CFNumberRef num = _CFNumberCreateWithString(connection->_alloc, value);
 866  
 867                  // If that succeeded, turn it into the actual size
 868                  if (num) {
 869                      
 870                      // Pull out the true expected count of bytes
 871                      CFNumberGetValue(num, kCFNumberSInt32Type, &size);
 872  
 873                      CFRelease(num);
 874                  }
 875  
 876                  // Received a bad content-length header
 877                  else {
 878  
 879                      if (body) CFRelease(body);
 880                      CFRelease(value);
 881  
 882                      // Establish an error
 883                      CFStreamError error = {kCFStreamErrorDomainHTTP, kCFStreamErrorHTTPParseFailure};
 884  
 885                      // Handle it just like an error.
 886                      _HttpConnectionHandleErrorOccurred(connection, &error);
 887  
 888                      break;
 889                  }
 890                  
 891                  CFRelease(value);
 892              }
 893  
 894              // If enough bytes haven't arrived, bail out now.
 895              if (length < size) {
 896                  if (body) CFRelease(body);
 897                  break;
 898              }
 899  
 900              // If the message is just right, inform the client of the message
 901              // and then exit since this is no more to process.
 902              else if (length == size) {
 903  
 904                  if (body) CFRelease(body);
 905                  
 906                  // Inform the client of the incoming request
 907                  if (connection->_server->_callbacks.didReceiveRequestCallBack != NULL) {
 908                      CFRetain(msg);
 909                      connection->_server->_callbacks.didReceiveRequestCallBack((_CFHTTPServerRef)connection->_server,
 910                                                                                msg,
 911                                                                                connection->_server->_ctxt.info);
 912                      CFRelease(msg);
 913                  }
 914  
 915                  break;
 916              }
 917  
 918              // There are too many bytes in the body
 919              else {
 920  
 921                  // Need to make new and truncate, 'cause the current one is too long.
 922                  CFDataRef newBody = CFDataCreate(connection->_alloc, CFDataGetBytePtr(body), size);
 923  
 924                  // Create a new request to capture the leftover bytes.
 925                  CFHTTPMessageRef newMsg = CFHTTPMessageCreateEmpty(connection->_alloc, TRUE);
 926                  
 927                  // Set the new body on the first request
 928                  CFHTTPMessageSetBody(msg, newBody);
 929  
 930                  // Toss the new body since it's retained by the request.
 931                  CFRelease(newBody);
 932  
 933                  // Inform the client of the incoming request
 934                  if (connection->_server->_callbacks.didReceiveRequestCallBack != NULL) {
 935                      CFRetain(msg);
 936                      connection->_server->_callbacks.didReceiveRequestCallBack((_CFHTTPServerRef)connection->_server,
 937                                                                                msg,
 938                                                                                connection->_server->_ctxt.info);
 939                      CFRelease(msg);
 940                  }
 941  
 942                  // Move on to the new message to handle it
 943                  msg = newMsg;
 944                  
 945                  // Put the new request in the requests list.
 946                  CFArrayAppendValue(connection->_requests, msg);
 947  
 948                  // Drop the retain count now since it's being held by the queue.
 949                  CFRelease(msg);
 950  
 951                  // Add the leftover bytes from the first request to the new one
 952                  if (!CFHTTPMessageAppendBytes(msg, CFDataGetBytePtr(body) + size, length - size)) {
 953  
 954                      // Establish an error
 955                      CFStreamError error = {kCFStreamErrorDomainHTTP, kCFStreamErrorHTTPParseFailure};
 956  
 957                      // Handle it just like an error.
 958                      _HttpConnectionHandleErrorOccurred(connection, &error);
 959  
 960                      CFRelease(body);
 961                      
 962                      break;
 963                  }
 964  
 965                  // Don't need the body.
 966                  CFRelease(body);
 967  
 968                  // Check to see if the new message is complete too.
 969                  if (!CFHTTPMessageIsHeaderComplete(msg))
 970                      break;	// Not done so bail.
 971  
 972                  // There is enough there so inform the client.
 973                  else {
 974  
 975                      // Assume the client is willing to take on the request.
 976                      Boolean handle = TRUE;
 977  
 978                      // Check the client to make sure this new message should be processed.
 979                      if (connection->_server->_callbacks.acceptNewRequestCallBack) {
 980  
 981                          handle = connection->_server->_callbacks.acceptNewRequestCallBack((_CFHTTPServerRef)connection->_server,
 982                                                                                            newMsg,
 983                                                                                            connection->_peer,
 984                                                                                            connection->_server->_ctxt.info);
 985                      }
 986  
 987                      if (!handle) {
 988                          
 989                          // Remove the connection from the pool
 990                          _HttpServerRemoveConnection(connection->_server, connection);
 991  
 992                          // Bail now because the current connection has been killed
 993                          break;
 994                      }
 995                  }
 996              }
 997          }
 998      }
 999  }
1000  
1001  
1002  /* static */ void
1003  _HttpConnectionHandleHasBytesAvailable(HttpConnection* connection) {
1004  
1005  	CFIndex bytes;
1006  	UInt8 buffer[kBufferSize];
1007  	
1008  	CFHTTPMessageRef msg;
1009  	
1010      // Get the count of requests currently known.
1011  	CFIndex i = CFArrayGetCount(connection->_requests);
1012  	
1013      // If there is, grab the last one with which to work
1014  	if (i != 0)
1015  		msg = (CFHTTPMessageRef)CFArrayGetValueAtIndex(connection->_requests, --i);
1016  		
1017  	else {
1018  		
1019          // There was no requests, so create a new one with which to work
1020  		msg = CFHTTPMessageCreateEmpty(connection->_alloc, TRUE);
1021  		CFArrayAppendValue(connection->_requests, msg);
1022  		CFRelease(msg);
1023  	}
1024  	
1025      // Try to read bytes off the wire
1026  	bytes = CFReadStreamRead(connection->_inStream, buffer, sizeof(buffer));
1027  	
1028      // Did it succeed?
1029  	if (bytes >= 0) {
1030  		
1031          Boolean complete = CFHTTPMessageIsHeaderComplete(msg);
1032          
1033          // Tickle the timer
1034          CFRunLoopTimerSetNextFireDate(connection->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds);
1035          
1036          // Attach read bytes to current request
1037          if (!CFHTTPMessageAppendBytes(msg, buffer, bytes)) {
1038  
1039              // Establish an error
1040              CFStreamError error = {kCFStreamErrorDomainHTTP, kCFStreamErrorHTTPParseFailure};
1041  
1042              // Handle it just like an error.
1043              _HttpConnectionHandleErrorOccurred(connection, &error);
1044  
1045              return;
1046          }
1047          
1048          // If the request is complete, handle it as appropriate.
1049          if (CFHTTPMessageIsHeaderComplete(msg)) {
1050              
1051              // Assume the client is willing to take on the request.
1052              Boolean handle = TRUE;
1053              
1054              // Check the client for sure (each message is checked once when it crosses
1055              // over from incomplete to complete.
1056              if (!complete && connection->_server->_callbacks.acceptNewRequestCallBack) {
1057              
1058                  handle = connection->_server->_callbacks.acceptNewRequestCallBack((_CFHTTPServerRef)connection->_server,
1059                                                                                    msg,
1060                                                                                    connection->_peer,
1061                                                                                    connection->_server->_ctxt.info);
1062              }
1063              
1064              if (handle)
1065                  _HttpConnectionHandleRequest(connection);
1066              
1067              else {
1068                  
1069                  // Remove the connection from the pool
1070                  _HttpServerRemoveConnection(connection->_server, connection);
1071              }
1072          }
1073  	}
1074  	
1075      // Let error conditions come in naturally through the event dispatch.
1076  }
1077  
1078  
1079  /* static */ void
1080  _HttpConnectionHandleCanAcceptBytes(HttpConnection* connection) {
1081  	
1082      // How are responses handled (read the "Description" at the top)?
1083      //
1084      // Responses have two parts: a CFHTTPMessageRef containing only headers and a CFReadStreamRef
1085      // which is a stream to the body contents.  These responses will be sent in the order in
1086      // which their respective requests were vended.
1087      //
1088      // A local buffer on the connection is used for all writing to the wire.  Buffered bytes are
1089      // always sent first.  An empty buffer signals the start of a new response.  If the buffer is
1090      // empty, the first, queued response's headers are serialized and placed in the buffer.
1091      //
1092      // Bytes in the buffer are sent to the wire.  If all bytes in the buffer were written, the
1093      // response's stream is read for bytes.  The read bytes are placed into the connection's
1094      // buffer.  This buffer will be used for writing when this function is called again.
1095      //
1096      // If the response's stream has been exhausted, that request-response pair is removed from
1097      // the connection's queue, and the buffer is left empty.  Since the buffer is empty, the
1098      // next response will be handled when this function is called again.
1099      //
1100      // At the end of each response, the headers are checked for the proper termination of the
1101      // open connection.  If a "Connection: close" header exists or if in default mode under
1102      // HTTP version 1.0, the connection will be terminated and dequeued from the server.
1103      
1104      // Check to make sure there are queued items.
1105      if (CFArrayGetCount(connection->_requests) != 0) {
1106          
1107          // Pull off the request and its related response information
1108          CFHTTPMessageRef request = (CFHTTPMessageRef)CFArrayGetValueAtIndex(connection->_requests, 0);
1109          CFArrayRef list = request ? (CFArrayRef)CFDictionaryGetValue(connection->_responses, request) : NULL;
1110          CFHTTPMessageRef response = list ? (CFHTTPMessageRef)CFArrayGetValueAtIndex(list, 0) : NULL;
1111          CFReadStreamRef stream = list ? (CFReadStreamRef)CFArrayGetValueAtIndex(list, 1) : NULL;
1112          
1113          // Only handle if there is a response ready to go
1114          if (list != NULL) {
1115          
1116              CFIndex bytesWritten;
1117          
1118              // If there are no buffered bytes, need to start the next request.
1119              if (CFDataGetLength(connection->_bufferedBytes) == 0) {
1120                  
1121                  // Serialize if for sending
1122                  CFDataRef serialized = CFHTTPMessageCopySerializedMessage(response);
1123                  
1124                  // Get rid of the old one before getting the new
1125                  CFRelease(connection->_bufferedBytes);
1126                  
1127                  // Use a mutable copy, because it gets sized down as bytes are sent.
1128                  connection->_bufferedBytes = CFDataCreateMutableCopy(connection->_alloc, 0, serialized);
1129                  
1130                  // Release the original.
1131                  CFRelease(serialized);
1132              }
1133              
1134              // Try writing the entire buffer
1135              bytesWritten = CFWriteStreamWrite(connection->_outStream,
1136                                                CFDataGetBytePtr(connection->_bufferedBytes),
1137                                                CFDataGetLength(connection->_bufferedBytes));
1138              
1139              // If successfully wrote, continue on.
1140              if (bytesWritten > 0) {
1141              
1142                  // Compute the new size of the buffer after the write
1143                  CFIndex newSize = CFDataGetLength(connection->_bufferedBytes) - bytesWritten;
1144                  
1145                  // Tickle the timer
1146                  CFRunLoopTimerSetNextFireDate(connection->_timer, CFAbsoluteTimeGetCurrent() + kTimeOutInSeconds);
1147          
1148                  // Move the remaining bytes down in the buffer
1149                  memmove(CFDataGetMutableBytePtr(connection->_bufferedBytes),
1150                          CFDataGetBytePtr(connection->_bufferedBytes) + bytesWritten,
1151                          newSize);
1152                          
1153                  // Resize the buffer to indicate what is left
1154                  CFDataSetLength(connection->_bufferedBytes, newSize);
1155                  
1156                  // If nothing left in the buffer, fill the buffer
1157                  if (newSize == 0) {
1158                  
1159                      CFIndex bytesRead;
1160                      
1161                      // If the response's stream isn't open yet, open it.
1162                      if (CFReadStreamGetStatus(stream) == kCFStreamStatusNotOpen)
1163                          CFReadStreamOpen(stream);
1164              
1165                      // Size the buffer for a full read
1166                      CFDataSetLength(connection->_bufferedBytes, kBufferSize);
1167                      
1168                      // Try reading a full buffer into the buffer
1169                      bytesRead = CFReadStreamRead(stream, CFDataGetMutableBytePtr(connection->_bufferedBytes), kBufferSize);
1170                  
1171                      // Size the buffer to what ever size was read if successful
1172                      if (bytesRead >= 0)
1173                          CFDataSetLength(connection->_bufferedBytes, bytesRead);
1174                      
1175                      // Was there an error?
1176                      if (bytesRead < 0) {
1177                          
1178                          // Get the error from the read stream
1179                          CFStreamError error = CFReadStreamGetError(stream);
1180                          
1181                          // Inform the client of the error.
1182                          _HttpConnectionHandleErrorOccurred(connection, &error);
1183                      }
1184                      
1185                      // Was this the end of the response's stream?
1186                      else if (bytesRead == 0) {
1187                          
1188                          // Get the HTTP version and the connection header from the response.
1189                          CFStringRef close = CFHTTPMessageCopyHeaderFieldValue(response, _kCFHTTPServerConnectionHeader);
1190                          CFStringRef version = CFHTTPMessageCopyVersion(response);
1191                          
1192                          // If no header, check the original request for one.
1193                          if (close == NULL)
1194                              close = CFHTTPMessageCopyHeaderFieldValue(request, _kCFHTTPServerConnectionHeader);
1195                          
1196                          // Inform the client of a successful send of the response.
1197                          if (connection->_server->_callbacks.didSendResponseCallBack != NULL) {
1198                              connection->_server->_callbacks.didSendResponseCallBack((_CFHTTPServerRef)connection->_server,
1199                                                                                      request,
1200                                                                                      response,
1201                                                                                      connection->_server->_ctxt.info);
1202                          }
1203                          
1204                          // Remove the request-response pair from the conneciton's queue
1205                          CFDictionaryRemoveValue(connection->_responses, request);
1206                          CFArrayRemoveValueAtIndex(connection->_requests, 0);
1207                          
1208                          // If there was a header and it said, "close," or if there was no header and HTTP version
1209                          // 1.0 is being used, then close the connection and remove it from the server.
1210                          if (((close != NULL) &&
1211                              CFStringCompare(close, _kCFHTTPServerConnectionClose, kCFCompareCaseInsensitive) == kCFCompareEqualTo) ||
1212                          	((close == NULL) && (version != NULL) &&
1213                              CFStringCompare(version, kCFHTTPVersion1_1, kCFCompareCaseInsensitive) != kCFCompareEqualTo))
1214                          {
1215                              _HttpServerRemoveConnection(connection->_server, connection);
1216                          }
1217                          if (close != NULL)
1218                              CFRelease(close);
1219                              
1220                          if (version != NULL)
1221                              CFRelease(version);
1222                      }
1223                  }
1224              }
1225          }
1226      }
1227  }
1228  
1229  
1230  /* static */ void
1231  _HttpConnectionHandleErrorOccurred(HttpConnection* connection, const CFStreamError* error) {
1232      
1233      CFArrayRef requests = CFArrayCreateCopy(connection->_alloc, connection->_requests);
1234      CFIndex i, count = CFArrayGetCount(requests);
1235      
1236      // Error-out each request in the queue
1237      for (i = 0; i < count; i++) {
1238  
1239          // Get the request and the response pair
1240          CFHTTPMessageRef request = (CFHTTPMessageRef)CFArrayGetValueAtIndex(connection->_requests, i);
1241          CFArrayRef list = (CFArrayRef)CFDictionaryGetValue(connection->_responses, request);
1242          
1243          // If there is a response and there is a client, inform the client of the error.
1244          if ((list != NULL) && (connection->_server->_callbacks.errorCallBack != NULL)) {
1245              connection->_server->_callbacks.errorCallBack((_CFHTTPServerRef)connection->_server,
1246                                                            error,
1247                                                            request,
1248                                                            (CFHTTPMessageRef)CFArrayGetValueAtIndex(list, 0),
1249                                                            connection->_server->_ctxt.info);
1250          }
1251      }
1252  
1253      CFRelease(requests);
1254      
1255      // Remove the connection from the pool
1256      _HttpServerRemoveConnection(connection->_server, connection);
1257  }
1258  
1259  
1260  /* static */ void
1261  _HttpConnectionHandleTimeOut(HttpConnection* connection) {
1262      
1263      // Establish an error
1264      CFStreamError error = {kCFStreamErrorDomainCFHTTPServer, kCFStreamErrorCFHTTPServerTimeout};
1265      
1266      // Handle it just like an error.
1267      _HttpConnectionHandleErrorOccurred(connection, &error);
1268  }
1269  
1270  
1271  
1272  /* static */ const void*
1273  _ArrayRetainCallBack(CFAllocatorRef allocator, const HttpConnection* connection) {
1274      
1275      return _HttpConnectionRetain((HttpConnection*)connection);
1276  }
1277  
1278  
1279  /* static */ void
1280  _ArrayReleaseCallBack(CFAllocatorRef allocator, const HttpConnection* connection) {
1281      
1282      return _HttpConnectionRelease((HttpConnection*)connection);
1283  }
1284  
1285  
1286  /* static */ void
1287  _ReadStreamCallBack(CFReadStreamRef inStream, CFStreamEventType type, HttpConnection* connection) {
1288  
1289      assert(inStream == connection->_inStream);
1290  	
1291      // Dispatch the event properly.
1292      switch (type) {
1293      
1294          case kCFStreamEventHasBytesAvailable:
1295              _HttpConnectionHandleHasBytesAvailable(connection);
1296              break;
1297         
1298          case kCFStreamEventErrorOccurred:
1299              {
1300                  CFStreamError error = CFReadStreamGetError(inStream);
1301                  _HttpConnectionHandleErrorOccurred(connection, &error);
1302              }
1303              break;
1304              
1305          default:
1306              break;
1307      }
1308  }
1309  
1310  
1311  /* static */ void
1312  _WriteStreamCallBack(CFWriteStreamRef outStream, CFStreamEventType type, HttpConnection* connection) {
1313  
1314  	assert(outStream == connection->_outStream);
1315  
1316  	// Dispatch the event properly.
1317      switch (type) {
1318  		case kCFStreamEventCanAcceptBytes:
1319  			_HttpConnectionHandleCanAcceptBytes(connection);
1320  			break;
1321  			
1322          case kCFStreamEventErrorOccurred:
1323              {
1324                  CFStreamError error = CFWriteStreamGetError(outStream);
1325                  _HttpConnectionHandleErrorOccurred(connection, &error);
1326              }
1327  			break;
1328              
1329          default:
1330              break;
1331      }
1332  }
1333  
1334  
1335  /* static */ void
1336  _TimerCallBack(CFRunLoopTimerRef timer, HttpConnection* connection) {
1337  
1338  	assert(timer == connection->_timer);
1339  
1340  	// Dispatch the timer event.
1341  	_HttpConnectionHandleTimeOut(connection);
1342  }
1343  
1344  
1345  /* static */ void
1346  _HttpServerAddConnection(HttpServer* server, HttpConnection* connection) {
1347  
1348      // Add the given connection to the list
1349      CFArrayAppendValue(server->_connections, connection);
1350  }
1351  
1352  
1353  /* static */ void
1354  _HttpServerRemoveConnection(HttpServer* server, HttpConnection* connection) {
1355      
1356      // Find the given connection in the list of connections
1357      CFMutableArrayRef connections = server->_connections;
1358      CFIndex i = CFArrayGetFirstIndexOfValue(connections,
1359                                              CFRangeMake(0, CFArrayGetCount(connections)),
1360                                              connection);
1361      
1362      // If it existed, remove it from the list.
1363      if (i != kCFNotFound)
1364          CFArrayRemoveValueAtIndex(connections, i);
1365  }
1366  
1367  
1368  /* static */ void
1369  _HttpServerHandleNewConnection(HttpServer* server, CFSocketNativeHandle sock) {
1370      
1371      CFAllocatorRef alloc = CFGetAllocator((_CFHTTPServerRef)server);
1372      
1373      // Assume the server will allow the connection.
1374      Boolean accepted = TRUE;
1375      
1376      // Find out if the client cares
1377      if (server->_callbacks.acceptNewConnectionCallBack) {
1378          
1379          uint8_t name[SOCK_MAXADDRLEN];
1380          socklen_t namelen = sizeof(name);
1381          CFDataRef peer = NULL;
1382          
1383          // Get the address of the peer.  **FIXME** this is less than optimal
1384          // since the peer name is copied again later when the connection is
1385          // created.
1386          if (0 == getpeername(sock, (struct sockaddr *)name, &namelen))
1387              peer = CFDataCreate(alloc, name, namelen);
1388          
1389          // Fail if the peer couldn't be established.
1390          if (!peer)
1391              accepted = FALSE;
1392              
1393          else {
1394          
1395              // See what the client says.
1396              accepted = server->_callbacks.acceptNewConnectionCallBack((_CFHTTPServerRef)server, peer, server->_ctxt.info);
1397              CFRelease(peer);
1398          }
1399      }
1400      
1401      if (accepted) {
1402      
1403          // Create a new incoming connection
1404          HttpConnection* connection = _HttpConnectionCreate(alloc, server, sock);
1405          
1406          // Add the connection to the server if it created.
1407          if (connection != NULL) {
1408              _HttpServerAddConnection(server, connection);
1409              _HttpConnectionRelease(connection);
1410          }
1411              
1412          else {
1413              
1414              // Create an error for the bad situation
1415              CFStreamError error = {kCFStreamErrorDomainCFHTTPServer, kCFStreamErrorCFHTTPServerInternal};
1416              
1417              // Handle the error
1418              _HttpServerHandleError(server, &error);
1419          }
1420      }
1421  }
1422  
1423  
1424  /* static */ void
1425  _HttpServerHandleError(HttpServer* server, const CFStreamError* error) {
1426  
1427  	// Inform the user of an error.
1428  	if (server->_callbacks.errorCallBack != NULL)
1429  		server->_callbacks.errorCallBack((_CFHTTPServerRef)server, error, NULL, NULL, server->_ctxt.info);
1430  }
1431  
1432  
1433  /* static */ void
1434  _ServerCallBack(_CFServerRef server, CFSocketNativeHandle sock, const CFStreamError* error, HttpServer* httpServer) {
1435  
1436      if (error->error == 0)
1437          _HttpServerHandleNewConnection(httpServer, sock);
1438          
1439      else
1440          _HttpServerHandleError(httpServer, error);
1441  }
1442  
1443  
1444  /* static */ CFNumberRef
1445  _CFNumberCreateWithString(CFAllocatorRef allocator, CFStringRef string) {
1446  
1447  	CFIndex i, length = CFStringGetLength(string);
1448  	UniChar* buffer = CFAllocatorAllocate(allocator, length * sizeof(buffer[0]), 0);
1449  	
1450  	SInt32 value = 0;
1451  	
1452  	CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
1453  	
1454  	for (i = 0; i < length; i++) {
1455  	
1456  		UniChar c = buffer[i];
1457  		
1458  		if ((c < '0') || (c > '9') || ((value * 10) < value)) {
1459  			CFAllocatorDeallocate(allocator, buffer);
1460  			return NULL;
1461  		}
1462  		
1463  		value *= 10;
1464  		value += (c - '0');
1465  	}
1466  	
1467  	CFAllocatorDeallocate(allocator, buffer);
1468  	
1469  	return CFNumberCreate(allocator, kCFNumberSInt32Type, &value);
1470  }
1471