(file) Return to http.c CVS log (file) (dir) Up to [OMI] / omi / http

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           ** 
   8           ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
   9           ** use this file except in compliance with the License. You may obtain a copy 
  10           ** of the License at 
  11           **
  12           **     http://www.apache.org/licenses/LICENSE-2.0 
  13           **
  14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15           ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
  16           ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
  17           ** MERCHANTABLITY OR NON-INFRINGEMENT. 
  18           **
  19           ** See the Apache 2 License for the specific language governing permissions 
  20           ** and limitations under the License.
  21           **
  22 mike  1.1 **==============================================================================
  23           */
  24           
  25           #include <assert.h>
  26           #include <ctype.h>
  27 krisbash 1.3 #include "httpcommon.h"
  28 mike     1.1 #include <sock/addr.h>
  29              #include <sock/sock.h>
  30              #include <sock/selector.h>
  31 krisbash 1.3 #include <pal/sleep.h>
  32 mike     1.1 #include <base/buf.h>
  33              #include <base/log.h>
  34              #include <base/result.h>
  35 krisbash 1.3 #include <pal/strings.h>
  36              #include <pal/format.h>
  37 mike     1.1 #include <base/paths.h>
  38 krisbash 1.3 #include <base/Strand.h>
  39 mike     1.1 
  40              #ifdef CONFIG_POSIX
  41              #include <openssl/ssl.h>
  42              #include <openssl/err.h>
  43              #include <pthread.h>
  44              #else
  45              /* ssl not supported in this configuration; just make compiler happy */
  46              typedef void SSL;
  47              typedef void SSL_CTX;
  48              #define SSL_CTX_free(c)
  49              #define SSL_new(c) 0
  50              #define SSL_free(c)
  51              #define SSL_set_fd(c,a) (a==a)
  52              #define SSL_read(c,a,b) 0
  53              #define SSL_write(c,a,b) 0
  54              #define SSL_get_error(c,e) e
  55              #define SSL_ERROR_WANT_WRITE 0
  56              #define SSL_ERROR_WANT_READ 1
  57              #define SSL_ERROR_SYSCALL 2
  58              
  59              #ifdef EWOULDBLOCK
  60 mike     1.1 # undef EWOULDBLOCK
  61              #endif
  62              #define EWOULDBLOCK 0
  63              
  64              #ifdef EINPROGRESS
  65              # undef EINPROGRESS
  66              #endif
  67              #define EINPROGRESS 0
  68              
  69              #define ERR_get_error() 0
  70              #define ERR_error_string_n(c,a,b) a[0]=0
  71              #define SSL_accept(c) 0
  72              
  73              #endif
  74              
  75 krisbash 1.3 #define FORCE_TRACING 0
  76 mike     1.1 
  77 krisbash 1.3 //------------------------------------------------------------------------------
  78 mike     1.1 
  79 krisbash 1.3 #define HTTPSOCKET_STRANDAUX_NEWREQUEST 0
  80 mike     1.1 
  81 krisbash 1.3 STRAND_DEBUGNAME1( HttpSocket, NewRequest );
  82 mike     1.1 
  83              /*
  84              **==============================================================================
  85              **
  86              ** Local definitions:
  87              **
  88              **==============================================================================
  89              */
  90              
  91              static const MI_Uint32 _MAGIC = 0xE0BB5FD3;
  92              static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
  93              static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
  94              static const size_t HTTP_MAX_CONTENT = 1024 * 1024;
  95              
  96              struct _Http
  97              {
  98 krisbash 1.3     MI_Uint32       magic;
  99 mike     1.1     Selector        internalSelector;
 100                  Selector*       selector;
 101 krisbash 1.3     OpenCallback    callbackOnNewConnection;
 102                  void*           callbackData;
 103                  SSL_CTX*        sslContext;
 104 mike     1.1     /* options: timeouts etc */
 105                  HttpOptions     options;
 106 krisbash 1.3     MI_Boolean      internalSelectorUsed;
 107 mike     1.1 };
 108              
 109              typedef struct _Http_Listener_SocketData
 110              {
 111                  /* based member*/
 112                  Handler     base;
 113              
 114                  MI_Boolean secure;
 115              }
 116              Http_Listener_SocketData;
 117              
 118              typedef enum _Http_RecvState
 119              {
 120                  RECV_STATE_HEADER,
 121                  RECV_STATE_CONTENT
 122              }
 123              Http_RecvState;
 124              
 125              typedef struct _Http_SR_SocketData
 126              {
 127 krisbash 1.3     Strand strand;
 128                  
 129                  Handler handler;    // Used on selector
 130              
 131                  Http* http;
 132 mike     1.1 
 133                  /* ssl part */
 134                  SSL* ssl;
 135                  MI_Boolean reverseOperations;  /*reverse read/write Events/Handlers*/
 136                  MI_Boolean acceptDone;
 137              
 138                  /* is server/provider is processing request 
 139                      (to disbale timeout) */
 140                  MI_Boolean requestIsBeingProcessed;
 141              
 142                  /* receiving data */
 143                  char* recvBuffer;
 144                  size_t recvBufferSize;
 145 krisbash 1.3     size_t receivedSize;
 146 mike     1.1     Http_RecvState recvingState;
 147                  HttpHeaders recvHeaders;
 148                  Page* recvPage;
 149 krisbash 1.3     HttpRequestMsg* request;    // request msg with the request page
 150 mike     1.1 
 151                  /* sending part */
 152                  Page* sendPage;
 153                  size_t sentSize;
 154                  Http_RecvState sendingState;
 155                  int httpErrorCode;
 156              
 157 krisbash 1.3     /* pending send message */
 158                  Message* savedSendMsg;
 159              
 160 mike     1.1     /* Enable tracing */
 161                  MI_Boolean enableTracing;
 162              }
 163              Http_SR_SocketData;
 164              
 165              /* helper functions result */
 166              typedef enum _Http_CallbackResult
 167              {
 168                  PRT_CONTINUE,
 169                  PRT_RETURN_TRUE,
 170                  PRT_RETURN_FALSE
 171              }
 172              Http_CallbackResult;
 173              
 174              MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
 175              {
 176                  return (MI_Uint8)tolower(x);
 177              }
 178              
 179              #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8)  | (((MI_Uint16)len)) )
 180              
 181 krisbash 1.3 _Return_type_success_(return == MI_TRUE)
 182 mike     1.1 static MI_Boolean _getNameValuePair(
 183 krisbash 1.3     _Inout_ CharPtr* line,
 184                  _Out_ CharPtr* value,
 185 mike     1.1     int*  nameHashCode )
 186              {
 187                  int len = 0;
 188                  char* p;
 189 krisbash 1.3     *value = 0;
 190 mike     1.1     /* find name end /hash-code */
 191              
 192 krisbash 1.3     if ((*line)[0] == 0)
 193                  {
 194                      trace_GetNameValuePair_Failed();
 195                      return MI_FALSE;
 196                  }
 197              
 198 mike     1.1     *nameHashCode =  _ToLower((MI_Uint8)(*line)[0])<<16;
 199              
 200 krisbash 1.3     for (len = 1; (*line)[len] && (*line)[len] != ':' && (*line)[len] != '\r'; len++ )
 201 mike     1.1         ;
 202              
 203                  if ((*line)[len] != ':')
 204 krisbash 1.3     {
 205                      trace_GetNameValuePair_Failed();
 206 mike     1.1         return MI_FALSE;
 207 krisbash 1.3     }
 208 mike     1.1 
 209                  *nameHashCode |=  (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
 210                  (*line)[len] = 0;
 211                  p = *line + len + 1;
 212              
 213                  /* skip spaces in value */
 214                  while (p[0] == ' ' || p[0] == '\t')
 215                      p++;
 216              
 217                  *value = p;
 218              
 219                  /* skip to end of line */
 220 krisbash 1.3     for ( ; p[0]; )
 221 mike     1.1     {
 222                      if (p[0] == '\r' && p[1] == '\n' && 
 223                          (p[2] != ' ' && p[2] != '\t') )
 224                      {
 225                          p[0] = 0;
 226                          (*line) = p + 2;
 227                          break;
 228                      }
 229                      p ++;
 230                  }
 231              
 232                  /* remove trailing spaces */
 233                  p--;
 234 krisbash 1.3 #ifdef _PREFAST_
 235              #pragma prefast (push)
 236              #pragma prefast (disable: 26001)
 237              #endif
 238                  /* disabling IPv6 OACR warnings - D3M bug 56 */
 239 mike     1.1     while (p[0] == ' ' || p[0] == '\t')
 240                      p--;
 241 krisbash 1.3 #ifdef _PREFAST_
 242              #pragma prefast (pop)
 243              #endif
 244 mike     1.1 
 245                  p[1] = 0;
 246              
 247                  return MI_TRUE;
 248              }
 249              
 250              static MI_Boolean _getHeaderField(
 251                  Http_SR_SocketData* handler,
 252 krisbash 1.3     _Inout_ CharPtr* line)
 253 mike     1.1 {
 254                  char* name = *line;
 255                  char* value = NULL;
 256                  int nameHashCode;
 257              
 258                  if (!_getNameValuePair(line, &value, &nameHashCode))
 259 krisbash 1.3     {
 260                      trace_GetNameValuePair_Failed();
 261 mike     1.1         return MI_FALSE;
 262 krisbash 1.3     }
 263              
 264              
 265              #if defined(CONFIG_ENABLE_HTTPHEADERS)
 266 mike     1.1 
 267 krisbash 1.3     /* Inject name-value into HTTP header array */
 268 mike     1.1 
 269 krisbash 1.3     if (handler->recvHeaders.headersSize < HTTP_MAX_HEADERS)
 270 mike     1.1     {
 271 krisbash 1.3         handler->recvHeaders.headers[handler->recvHeaders.headersSize].name =
 272                          name;
 273                      handler->recvHeaders.headers[handler->recvHeaders.headersSize].value =
 274                          value;
 275                      handler->recvHeaders.headersSize++;
 276                  }
 277              
 278              #endif /* defined(CONFIG_ENABLE_HTTPHEADERS) */
 279 mike     1.1 
 280 krisbash 1.3     /* Convert specified headers to static fields */
 281 mike     1.1 
 282 krisbash 1.3     switch (nameHashCode)
 283                  {
 284                      case (_HashCode('c','e',12)): /*Content-Type*/
 285 mike     1.1         {
 286 krisbash 1.3             if (Strcasecmp(name,"Content-Type") == 0)
 287                              ParseContentType(&handler->recvHeaders, value);
 288              
 289                          break;
 290 mike     1.1         }
 291 krisbash 1.3         case (_HashCode('c','h',14)): /*Content-Length*/
 292                      {
 293                          if (Strcasecmp(name,"Content-Length") == 0)
 294                          {
 295                              handler->recvHeaders.contentLength = (size_t)Strtoull(value, 
 296                                  NULL, 10);
 297 mike     1.1 
 298 krisbash 1.3                 if ( handler->recvHeaders.contentLength > HTTP_MAX_CONTENT )
 299                              {
 300                                  trace_ContentLength_MaxCheck_Failed();
 301                                  return MI_FALSE;
 302                              }
 303                          }
 304                          break;
 305                      }
 306                      case (_HashCode('a','n',13)): /*Authorization*/
 307 mike     1.1         {
 308 krisbash 1.3             if (Strcasecmp(name,"Authorization") == 0)
 309 mike     1.1             {
 310 krisbash 1.3                 if( !ParseAuthorization(&handler->recvHeaders,value) )
 311 mike     1.1                 {
 312                                  return MI_FALSE;
 313                              }
 314                          }
 315 krisbash 1.3             break;
 316 mike     1.1         }
 317 krisbash 1.3         case (_HashCode('u','t',10)):
 318                      {
 319                          /* Remember the User-Agent for later use */
 320                          if (Strcasecmp(name, "User-Agent") == 0)
 321                          {
 322                              handler->recvHeaders.userAgent = value;
 323                          }
 324                          break;
 325                      }
 326                      default:
 327                          break;
 328 mike     1.1 
 329                  }
 330              
 331                  return MI_TRUE;
 332              }
 333              
 334              static MI_Boolean _getRequestLine(
 335                  Http_SR_SocketData* handler,
 336 krisbash 1.3     _Inout_ CharPtr* line)
 337 mike     1.1 {
 338                  size_t index;
 339                  /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 340                      Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
 341                  */
 342              
 343 krisbash 1.3     if ((*line)[0] == 0)
 344                  {
 345                      trace_GetRequestLine_failed();
 346                      return MI_FALSE;
 347                  }
 348              
 349 mike     1.1     /* skip to end of line */
 350 krisbash 1.3     for ( index = 1; (*line)[index] && index < handler->receivedSize; index++ )
 351 mike     1.1     {
 352 krisbash 1.3         if ((*line)[index-1] == '\r' && (*line)[index] == '\n')
 353 mike     1.1         {
 354                          (*line) = (*line) + index + 1;
 355                          return MI_TRUE;
 356                      }
 357                  }
 358              
 359 krisbash 1.3     trace_GetRequestLine_failed();
 360              
 361 mike     1.1     return MI_FALSE;
 362              }
 363              
 364              static MI_Result _Sock_ReadAux(
 365                  Http_SR_SocketData* handler,
 366                  void* buf,
 367                  size_t buf_size,
 368                  size_t* sizeRead)
 369              {
 370                  int res;
 371              
 372                  if (!handler->ssl)
 373 krisbash 1.3         return Sock_Read(handler->handler.sock, buf, buf_size, sizeRead);
 374 mike     1.1 
 375 krisbash 1.3     handler->handler.mask &= ~SELECTOR_WRITE;
 376                  handler->handler.mask |= SELECTOR_READ;
 377 mike     1.1     handler->reverseOperations = MI_FALSE;
 378              
 379                  *sizeRead = 0;
 380              
 381                  if (handler->acceptDone)
 382                  {
 383                      res = SSL_read(handler->ssl, buf, buf_size);
 384                  }
 385                  else
 386                  {
 387                      res = SSL_accept(handler->ssl);
 388 krisbash 1.3 
 389 mike     1.1         if ( res > 0 )
 390                      {
 391                          /* we are done with accpet */
 392                          handler->acceptDone = MI_TRUE;
 393                          return _Sock_ReadAux(handler,buf,buf_size,sizeRead);
 394                      }
 395                      /* perform regular error checking */
 396                  }
 397              
 398                  if ( res == 0 )
 399                      return MI_RESULT_OK;    /* connection closed */
 400              
 401                  if ( res > 0 )
 402                  {
 403                      *sizeRead = res;
 404                      return MI_RESULT_OK;    /* ok */
 405                  }
 406              
 407                  switch (SSL_get_error(handler->ssl, res))
 408                  {
 409                  case SSL_ERROR_WANT_WRITE:
 410 mike     1.1         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 411 krisbash 1.3         handler->handler.mask |= SELECTOR_WRITE;
 412                      handler->handler.mask &= ~SELECTOR_READ;
 413              
 414 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 415              
 416                  case SSL_ERROR_WANT_READ:
 417                      return MI_RESULT_WOULD_BLOCK;
 418              
 419                  case SSL_ERROR_SYSCALL:
 420                      if (EAGAIN == errno ||
 421                          EWOULDBLOCK == errno ||
 422                          EINPROGRESS == errno)
 423                          return MI_RESULT_WOULD_BLOCK;
 424              
 425 krisbash 1.3         trace_SSLRead_UnexpectedSysError(errno);
 426 mike     1.1         break;
 427              
 428                  default:
 429                      {
 430                          /* print error */
 431                          unsigned long err = ERR_get_error();
 432                          while (err)
 433                          {
 434                              char err_txt[200];
 435                              ERR_error_string_n(err, err_txt, sizeof(err_txt));
 436              
 437 krisbash 1.3                 trace_SSLRead_Error((int)err, scs(err_txt));
 438 mike     1.1                 err = ERR_get_error();
 439                          }
 440                      }
 441                      break;
 442                  }
 443                  return MI_RESULT_FAILED;
 444              }
 445              
 446              static MI_Result _Sock_WriteAux(
 447                  Http_SR_SocketData* handler,
 448                  void* buf,
 449                  size_t buf_size,
 450                  size_t* sizeWritten)
 451              {
 452                  int res;
 453              
 454                  if (!handler->ssl)
 455 krisbash 1.3         return Sock_Write(handler->handler.sock, buf, buf_size, sizeWritten);
 456 mike     1.1 
 457                  /* Do not clear READ flag, since 'close' notification
 458                  delivered as READ event*/
 459 krisbash 1.3     handler->handler.mask &= ~SELECTOR_READ; 
 460                  handler->handler.mask |= SELECTOR_WRITE;
 461 mike     1.1     handler->reverseOperations = MI_FALSE;
 462              
 463                  *sizeWritten = 0;
 464                  res = SSL_write(handler->ssl, buf, buf_size);
 465              
 466                  if ( res == 0 )
 467                      return MI_RESULT_OK;    /* connection closed */
 468              
 469                  if ( res > 0 )
 470                  {
 471                      *sizeWritten = res;
 472                      return MI_RESULT_OK;    /* ok */
 473                  }
 474              
 475                  switch (SSL_get_error(handler->ssl, res))
 476                  {
 477                  case SSL_ERROR_WANT_WRITE:
 478                      return MI_RESULT_WOULD_BLOCK;
 479              
 480                  case SSL_ERROR_WANT_READ:
 481                      handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 482 krisbash 1.3         handler->handler.mask |= SELECTOR_READ;
 483                      handler->handler.mask &= ~SELECTOR_WRITE;
 484 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 485              
 486                  case SSL_ERROR_SYSCALL:
 487                      if (EAGAIN == errno ||
 488                          EWOULDBLOCK == errno ||
 489                          EINPROGRESS == errno)
 490                          return MI_RESULT_WOULD_BLOCK;
 491              
 492 krisbash 1.3         trace_SSLWrite_UnexpectedSysError(errno);
 493 mike     1.1         break;
 494              
 495                  default:
 496                      break;
 497                  }
 498                  return MI_RESULT_FAILED;
 499              }
 500              
 501              static void _WriteTraceFile(PathID id, void* data, size_t size)
 502              {
 503 krisbash 1.3 #ifdef CONFIG_POSIX
 504 mike     1.1     static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
 505 krisbash 1.3 #else
 506                  /* TODO: How to synchronize logging */
 507              #endif
 508 mike     1.1     const char* path;
 509                  
 510 krisbash 1.3     if (!(path = OMI_GetPath(id)))
 511 mike     1.1         return;
 512              
 513 krisbash 1.3 #ifdef CONFIG_POSIX
 514 mike     1.1     pthread_mutex_lock(&s_mutex);
 515 krisbash 1.3 #else
 516                  /* TODO: How to synchronize logging */
 517              #endif
 518 mike     1.1     {
 519                      FILE* out = fopen(path, "a");
 520              
 521                      if (out)
 522 krisbash 1.3         {
 523 mike     1.1             fwrite(data, 1, size, out);
 524 krisbash 1.3             fclose(out);
 525                      }
 526                      else
 527                      {
 528                          trace_CannotOpenHttptraceFile(path, errno);
 529                      }
 530 mike     1.1     }
 531 krisbash 1.3 #ifdef CONFIG_POSIX
 532 mike     1.1     pthread_mutex_unlock(&s_mutex);
 533 krisbash 1.3 #else
 534                  /* TODO: How to synchronize logging */
 535              #endif
 536 mike     1.1 }
 537              
 538              INLINE MI_Result _Sock_Read(
 539                  Http_SR_SocketData* handler,
 540                  void* buf,
 541                  size_t buf_size,
 542                  size_t* sizeRead)
 543              {
 544                  MI_Result r = _Sock_ReadAux(handler, buf, buf_size, sizeRead);
 545              
 546 krisbash 1.3     if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
 547 mike     1.1     {
 548                      _WriteTraceFile(ID_HTTPRECVTRACEFILE, buf, *sizeRead);
 549                  }
 550              
 551                  return r;
 552              }
 553              
 554              INLINE MI_Result _Sock_Write(
 555                  Http_SR_SocketData* handler,
 556                  void* buf,
 557                  size_t buf_size,
 558                  size_t* sizeWritten)
 559              {
 560                  MI_Result r = _Sock_WriteAux(handler, buf, buf_size, sizeWritten);
 561              
 562 krisbash 1.3     if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
 563 mike     1.1     {
 564                      _WriteTraceFile(ID_HTTPSENDTRACEFILE, buf, *sizeWritten);
 565                  }
 566              
 567                  return r;
 568              }
 569              
 570              static Http_CallbackResult _ReadHeader(
 571                  Http_SR_SocketData* handler)
 572              {
 573                  char* buf;
 574                  char* currentLine;
 575                  char* data;
 576                  size_t buf_size, received, index;
 577                  MI_Result r;
 578                  MI_Boolean fullHeaderReceived = MI_FALSE;
 579              
 580                  /* are we done with header? */
 581                  if (handler->recvingState == RECV_STATE_CONTENT)
 582                      return PRT_CONTINUE;
 583              
 584 krisbash 1.3     buf = handler->recvBuffer + handler->receivedSize;
 585                  buf_size = handler->recvBufferSize - handler->receivedSize;
 586 mike     1.1     received = 0;
 587              
 588                  r = _Sock_Read(handler, buf, buf_size, &received);
 589              
 590                  if ( r == MI_RESULT_OK && 0 == received )
 591                      return PRT_RETURN_FALSE; /* conection closed */
 592              
 593                  if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 594                      return PRT_RETURN_FALSE;
 595              
 596                  if (!received)
 597                      return PRT_RETURN_TRUE;
 598              
 599 krisbash 1.3     handler->receivedSize += received;
 600 mike     1.1 
 601                  /* did we get full header? */
 602                  buf = handler->recvBuffer;
 603 krisbash 1.3     for ( index = 3; index < handler->receivedSize; index++ )
 604 mike     1.1     {
 605                      if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
 606                          buf[index-2] == '\n' && buf[index] == '\n' )
 607                      {
 608                          fullHeaderReceived = MI_TRUE;
 609                          break;
 610                      }
 611                  }
 612              
 613                  if (!fullHeaderReceived )
 614                  {
 615 krisbash 1.3         if ( handler->receivedSize <  handler->recvBufferSize )
 616 mike     1.1             return PRT_RETURN_TRUE; /* continue reading */
 617              
 618                      if ( handler->recvBufferSize < MAX_HEADER_SIZE )
 619                      {
 620 krisbash 1.3             buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
 621 mike     1.1 
 622                          if (!buf)
 623                              return PRT_RETURN_FALSE;
 624              
 625                          handler->recvBufferSize *= 2;
 626                          handler->recvBuffer = buf;
 627                          return _ReadHeader(handler);
 628                      }
 629                      else
 630                      {
 631                          /* http header is too big - drop connection */
 632 krisbash 1.3             trace_HttpHeaderIsTooBig();
 633 mike     1.1             return PRT_RETURN_FALSE;
 634                      }
 635                  }
 636              
 637                  /* consume data */
 638                  currentLine = buf;
 639                  data = buf + index + 1; /* pointer to data in case we got some */
 640              
 641                  if (!_getRequestLine(handler, &currentLine))
 642                      return PRT_RETURN_FALSE;
 643              
 644              
 645                  while ((data-currentLine) > 3)
 646                  {
 647                      if (!_getHeaderField(handler, &currentLine))
 648                          return PRT_RETURN_FALSE;
 649              
 650                  }
 651              
 652                  /* Allocate zero-terminated buffer */
 653 krisbash 1.3     handler->recvPage = (Page*)PAL_Malloc(sizeof(Page) + handler->recvHeaders.contentLength + 1);
 654 mike     1.1 
 655                  if (!handler->recvPage)
 656                      return PRT_RETURN_FALSE;
 657              
 658                  ((char*)(handler->recvPage + 1))[handler->recvHeaders.contentLength] = 0;
 659              
 660                  handler->recvPage->u.s.size = (unsigned int)handler->recvHeaders.contentLength;
 661                  handler->recvPage->u.s.next = 0;
 662              
 663 krisbash 1.3     handler->receivedSize -= index + 1;
 664 mike     1.1 
 665                  /* Verify that we have not more than 'content-length' bytes in buffer left 
 666                      If we hvae more, assuming http client is invalid and drop connection */
 667 krisbash 1.3     if (handler->receivedSize > handler->recvHeaders.contentLength)
 668 mike     1.1     {
 669 krisbash 1.3         trace_HttpPayloadIsBiggerThanContentLength();
 670 mike     1.1         return PRT_RETURN_FALSE;
 671                  }
 672              
 673 krisbash 1.3     memcpy( handler->recvPage + 1, data, handler->receivedSize );
 674 mike     1.1     handler->recvingState = RECV_STATE_CONTENT;
 675              
 676                  return PRT_CONTINUE;
 677              }
 678              
 679              static Http_CallbackResult _ReadData(
 680                  Http_SR_SocketData* handler)
 681              {
 682                  char* buf;
 683                  size_t buf_size, received;
 684                  MI_Result r;
 685 krisbash 1.3     HttpRequestMsg* msg;
 686 mike     1.1 
 687                  /* are we in the right state? */
 688                  if (handler->recvingState != RECV_STATE_CONTENT)
 689                      return PRT_RETURN_FALSE;
 690              
 691 krisbash 1.3     buf = ((char*)(handler->recvPage + 1)) + handler->receivedSize;
 692                  buf_size = handler->recvHeaders.contentLength - handler->receivedSize;
 693 mike     1.1     received = 0;
 694              
 695                  if (buf_size)
 696                  {
 697                      r = _Sock_Read(handler, buf, buf_size, &received);
 698              
 699                      if ( r == MI_RESULT_OK && 0 == received )
 700                          return PRT_RETURN_FALSE; /* conection closed */
 701              
 702                      if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 703                          return PRT_RETURN_FALSE;
 704              
 705 krisbash 1.3         handler->receivedSize += received;
 706 mike     1.1     }
 707              
 708                  /* did we get all data? */
 709              
 710 krisbash 1.3     if ( handler->receivedSize != handler->recvHeaders.contentLength )
 711 mike     1.1         return PRT_RETURN_TRUE;
 712               
 713 krisbash 1.3     msg = HttpRequestMsg_New(handler->recvPage, &handler->recvHeaders);
 714              
 715                  if( NULL == msg )
 716                  {
 717                      trace_HTTP_RequestAllocFailed( handler );
 718              
 719                      if (handler->recvPage)
 720                      {
 721                          PAL_Free(handler->recvPage);
 722                          handler->recvPage = NULL; /* clearing this out so that caller does not double-free it */
 723                      }
 724              
 725                      return PRT_RETURN_FALSE;
 726                  }
 727                  
 728 mike     1.1     handler->requestIsBeingProcessed = MI_TRUE;
 729              
 730 krisbash 1.3     // the page will be owned by receiver of this message
 731                  DEBUG_ASSERT( NULL == handler->request );
 732                  handler->request = msg;
 733                  Strand_ScheduleAux( &handler->strand, HTTPSOCKET_STRANDAUX_NEWREQUEST );
 734 mike     1.1 
 735                  handler->recvPage = 0;
 736 krisbash 1.3     handler->receivedSize = 0;
 737 mike     1.1     memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 738                  handler->recvingState = RECV_STATE_HEADER;
 739                  return PRT_CONTINUE;
 740              }
 741              
 742              static MI_Boolean _RequestCallbackRead(
 743                  Http_SR_SocketData* handler)
 744              {
 745                  switch (_ReadHeader(handler))
 746                  {
 747                  case PRT_CONTINUE: break;
 748                  case PRT_RETURN_TRUE: return MI_TRUE;
 749                  case PRT_RETURN_FALSE: return MI_FALSE;
 750                  }
 751              
 752                  switch (_ReadData(handler))
 753                  {
 754                  case PRT_CONTINUE: break;
 755                  case PRT_RETURN_TRUE: return MI_TRUE;
 756                  case PRT_RETURN_FALSE: return MI_FALSE;
 757                  }
 758 mike     1.1     return MI_TRUE;
 759              }
 760              
 761              /* length of longest description - has to be updated if descriptions are updated */
 762              #define HTTP_LONGEST_ERROR_DESCRIPTION 50
 763              static const char* _GetHttpErrorCodeDescription(
 764                  int httpErrorCode )
 765              {
 766                  switch (httpErrorCode)
 767                  {
 768                  case 200:
 769                      return "OK";
 770              
 771                  case 400:
 772                      return "Bad Request";
 773              
 774                  case 401:
 775                      return "Unauthorized";
 776              
 777                  case 500:
 778                      return "Internal Server Error";
 779 mike     1.1     }
 780                  return "Error";
 781              }
 782              
 783 krisbash 1.3 /* 
 784               * Common clean up function that reverts the changes made when preparing 
 785               * the strand for a write.
 786               */
 787              static void _ResetWriteState(
 788                  Http_SR_SocketData* socketData )
 789              {
 790                  if (socketData->sendPage)
 791                  {
 792                      PAL_Free(socketData->sendPage);
 793                      socketData->sendPage = 0;
 794                  }
 795                  socketData->httpErrorCode = 0;
 796                  socketData->sentSize = 0;
 797                  socketData->sendingState = RECV_STATE_HEADER;
 798                  socketData->handler.mask &= ~SELECTOR_WRITE;
 799                  socketData->handler.mask |= SELECTOR_READ;
 800              }
 801              
 802 mike     1.1 static Http_CallbackResult _WriteHeader(
 803                  Http_SR_SocketData* handler)
 804              {
 805              #define RESPONSE_HEADER_FMT \
 806                  "HTTP/1.1 %d %s\r\n"   \
 807                  "Content-Length: %d\r\n"\
 808                  "Connection: Keep-Alive\r\n"\
 809                  "Content-Type: application/soap+xml;charset=UTF-8\r\n"\
 810                  "\r\n"
 811              
 812 krisbash 1.3 #define RESPONSE_HEADER_NO_AUTH_FMT "HTTP/1.1 %d %s\r\n\r\n"
 813              
 814              #define RESPONSE_HEADER_401_ERROR_FMT \
 815                  "HTTP/1.1 %d %s \r\n" \
 816                  HTTP_WWWAUTHENTICATE_BASIC\
 817                  "\r\n"\
 818                  "Content-Length: 0\r\n"\
 819                  "\r\n"
 820              
 821 mike     1.1 /*    "SOAPAction: http://schemas.xmlsoap.org/ws/2004/08/addressing/fault\r\n"\ */
 822              
 823                  char currentLine[sizeof(RESPONSE_HEADER_FMT) + 
 824                      10 /* content length */ + 
 825                      10 /*error code*/ + 
 826                      HTTP_LONGEST_ERROR_DESCRIPTION /* code descirpiton */ ];
 827                  char* buf;
 828                  size_t buf_size, sent;
 829                  MI_Result r;
 830              
 831                  /* Do we have any data to send? */
 832                  if (!handler->sendPage && 0 == handler->httpErrorCode)
 833                      return PRT_RETURN_TRUE;
 834              
 835                  /* are we done with header? */
 836                  if (handler->sendingState == RECV_STATE_CONTENT)
 837                      return PRT_CONTINUE;
 838              
 839                  if (handler->sendPage)
 840                  {
 841                      buf_size = (size_t)Snprintf(
 842 mike     1.1             currentLine,
 843                          sizeof(currentLine),
 844                          RESPONSE_HEADER_FMT, 
 845                          (int)handler->httpErrorCode, 
 846                          _GetHttpErrorCodeDescription(handler->httpErrorCode),
 847                          (int)handler->sendPage->u.s.size );
 848                  }
 849                  else
 850                  {
 851 krisbash 1.3         int httpErrorCode = (int)handler->httpErrorCode;
 852                      /*
 853                      Check the error code and in case it is "HTTP_ERROR_CODE_UNAUTHORIZED" (401), then we need to send the 
 854                      "WWW-Authenticate" header field. Since right now we only support "Basic" auth so the header will contains 
 855                      "WWW-Authenticate: Basic realm=\"WSMAN\".
 856                      */
 857                      char * response =  (httpErrorCode == HTTP_ERROR_CODE_UNAUTHORIZED) ? RESPONSE_HEADER_401_ERROR_FMT : RESPONSE_HEADER_NO_AUTH_FMT;
 858                      
 859 mike     1.1         buf_size = (size_t)Snprintf(
 860                          currentLine,
 861                          sizeof(currentLine),
 862 krisbash 1.3             response, 
 863                          httpErrorCode,
 864 mike     1.1             _GetHttpErrorCodeDescription(handler->httpErrorCode));
 865                  }
 866              
 867                  buf = currentLine + handler->sentSize;
 868              
 869                  sent = 0;
 870              
 871                  r = _Sock_Write(handler, buf, buf_size - handler->sentSize, &sent);
 872              
 873                  if ( r == MI_RESULT_OK && 0 == sent )
 874                      return PRT_RETURN_FALSE; /* conection closed */
 875              
 876                  if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 877                      return PRT_RETURN_FALSE;
 878              
 879                  if (!sent)
 880                      return PRT_RETURN_TRUE;
 881              
 882                  handler->sentSize += sent;
 883              
 884                  if (handler->sentSize < buf_size)
 885 mike     1.1         return PRT_RETURN_TRUE;
 886              
 887                  handler->sentSize = 0;
 888                  handler->sendingState = RECV_STATE_CONTENT;
 889                  return PRT_CONTINUE;
 890              }
 891              
 892              static Http_CallbackResult _WriteData(
 893                  Http_SR_SocketData* handler)
 894              {
 895                  char* buf;
 896                  size_t buf_size, sent;
 897                  MI_Result r;
 898              
 899                  /* are we in the right state? */
 900                  if (handler->sendingState != RECV_STATE_CONTENT)
 901                      return PRT_RETURN_FALSE;
 902              
 903                  if (!handler->sendPage)
 904                  {   /* no content*/
 905 krisbash 1.3         _ResetWriteState( handler );
 906 mike     1.1         return PRT_CONTINUE;
 907                  }
 908              
 909                  buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
 910                  buf_size = handler->sendPage->u.s.size - handler->sentSize;
 911                  sent = 0;
 912              
 913                  r = _Sock_Write(handler, buf, buf_size, &sent);
 914              
 915                  if ( r == MI_RESULT_OK && 0 == sent )
 916                      return PRT_RETURN_FALSE; /* conection closed */
 917              
 918                  if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 919                      return PRT_RETURN_FALSE;
 920              
 921                  handler->sentSize += sent;
 922              
 923                  /* did we get all data? */
 924              
 925                  if ( handler->sentSize != handler->sendPage->u.s.size )
 926                      return PRT_RETURN_TRUE;
 927 mike     1.1  
 928 krisbash 1.3     _ResetWriteState( handler );
 929 mike     1.1 
 930                  return PRT_CONTINUE;
 931              }
 932              
 933              static MI_Boolean _RequestCallbackWrite(
 934                  Http_SR_SocketData* handler)
 935              {
 936                  switch (_WriteHeader(handler))
 937                  {
 938                  case PRT_CONTINUE: break;
 939                  case PRT_RETURN_TRUE: return MI_TRUE;
 940 krisbash 1.3     case PRT_RETURN_FALSE: 
 941                      _ResetWriteState( handler );
 942                      return MI_FALSE;
 943 mike     1.1     }
 944              
 945                  switch (_WriteData(handler))
 946                  {
 947                  case PRT_CONTINUE: break;
 948                  case PRT_RETURN_TRUE: return MI_TRUE;
 949 krisbash 1.3     case PRT_RETURN_FALSE: 
 950                      _ResetWriteState( handler );
 951                      return MI_FALSE;
 952 mike     1.1     }
 953                  return MI_TRUE;
 954              }
 955              
 956              static MI_Boolean _RequestCallback(
 957                  Selector* sel,
 958                  Handler* handlerIn,
 959                  MI_Uint32 mask, 
 960                  MI_Uint64 currentTimeUsec)
 961              {
 962 krisbash 1.3     Http_SR_SocketData* handler = FromOffset( Http_SR_SocketData, handler, handlerIn );
 963 mike     1.1     sel=sel;
 964              
 965                  if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
 966                      ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )
 967                  {
 968                      if (!_RequestCallbackRead(handler))
 969 krisbash 1.3         {
 970                          trace_RequestCallbackRead_Failed(handler);
 971 mike     1.1             return MI_FALSE;
 972 krisbash 1.3         }
 973 mike     1.1     }
 974              
 975                  if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
 976                      ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )
 977                  {
 978                      if (!_RequestCallbackWrite(handler))
 979 krisbash 1.3         {
 980                          trace_RequestCallbackWrite_Failed();
 981 mike     1.1             return MI_FALSE;
 982 krisbash 1.3         }
 983 mike     1.1     }
 984                  
 985                  /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
 986                  if (mask & (SELECTOR_READ | SELECTOR_WRITE))
 987                  {
 988 krisbash 1.3         Http* self = (Http*)handler->handler.data;
 989 mike     1.1 
 990                      if (handler->requestIsBeingProcessed)
 991                      {
 992                          /* since request is processed by server, disable timeout for this period */
 993 krisbash 1.3             handler->handler.fireTimeoutAt = TIME_NEVER;
 994 mike     1.1         }
 995                      else
 996                      {
 997                          /* Use configuration timeout */
 998 krisbash 1.3             handler->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
 999 mike     1.1         }
1000                  }
1001              
1002                  /* Close conenction by timeout */
1003                  if (mask & SELECTOR_TIMEOUT)
1004 krisbash 1.3     {
1005                      trace_ConnectionClosed_Timeout();
1006 mike     1.1         return MI_FALSE;
1007 krisbash 1.3     }
1008 mike     1.1 
1009                  if ((mask & SELECTOR_REMOVE) != 0 ||
1010                      (mask & SELECTOR_DESTROY) != 0)
1011                  {
1012                      if (handler->ssl)
1013                          SSL_free(handler->ssl);
1014              
1015 krisbash 1.3         trace_SocketClose_REMOVEDESTROY();
1016 mike     1.1 
1017 krisbash 1.3         Sock_Close(handler->handler.sock);
1018              
1019                      // Free the savedSendMsg and ACK it to prevent leaks when a non-io thread
1020                      // writes to the socket, but it cannot be read because of an error or a
1021                      // ECONNRESET.
1022                      if (handler->savedSendMsg)
1023                      {
1024                          Message_Release(handler->savedSendMsg);
1025                          handler->savedSendMsg = NULL;
1026                          DEBUG_ASSERT(handler->strand.info.otherAckPending);
1027                          Strand_ScheduleAck( &handler->strand );
1028                      }
1029 mike     1.1 
1030                      if (handler->recvPage)
1031 krisbash 1.3             PAL_Free(handler->recvPage);
1032 mike     1.1 
1033                      if (handler->sendPage)
1034 krisbash 1.3             PAL_Free(handler->sendPage);
1035              
1036                      PAL_Free(handler->recvBuffer);
1037                      // handler deleted on its own strand
1038 mike     1.1 
1039 krisbash 1.3         // notify next stack layer 
1040                      // (only after internal data has been deleted as this may delete the object)
1041                      Strand_ScheduleClose( &handler->strand );
1042 mike     1.1     }
1043              
1044                  return MI_TRUE;
1045              }
1046              
1047 krisbash 1.3 /*
1048              **==============================================================================
1049              */
1050              
1051              static void _SendIN_IO_thread_HttpSocket(void* self_, Message* message)
1052              {
1053                  Http_SR_SocketData* sendSock = (Http_SR_SocketData*)self_;
1054                  HttpResponseMsg * response = (HttpResponseMsg *)message;
1055              
1056                  DEBUG_ASSERT( sendSock );
1057                  DEBUG_ASSERT( HttpResponseMsgTag == message->tag );
1058              
1059                  /* validate handler */
1060              
1061                  if (MI_RESULT_OK != Selector_ContainsHandler(
1062                          sendSock->http->selector, &sendSock->handler ) )
1063                  {
1064                      trace_SendIN_IO_thread_HttpSocket_InvalidHandler(sendSock);
1065                      return;
1066                  }
1067              
1068 krisbash 1.3     sendSock->requestIsBeingProcessed = MI_FALSE;
1069              
1070                  sendSock->handler.mask |= SELECTOR_WRITE;
1071                  sendSock->handler.mask &= ~SELECTOR_READ;
1072              
1073                  // Now we take ownership of the page
1074                  sendSock->sendPage = response->page;
1075                  response->page = NULL;
1076                  sendSock->httpErrorCode = response->httpErrorCode;
1077              
1078                  sendSock->sentSize = 0;
1079                  sendSock->sendingState = RECV_STATE_HEADER;
1080              
1081                  // Done after response->page is NULL'd to prevent early release
1082                  // of that memory in the message's destructor
1083                  DEBUG_ASSERT( sendSock->savedSendMsg );
1084                  Message_Release(sendSock->savedSendMsg);
1085                  sendSock->savedSendMsg = NULL;
1086              
1087                  if( !_RequestCallbackWrite(sendSock) )
1088                  {
1089 krisbash 1.3         trace_SendIN_IO_thread_HttpSocket_WriteFailed();
1090                  }
1091              
1092                  Strand_ScheduleAck( &sendSock->strand );
1093              }
1094              
1095              void _HttpSocket_Post( _In_ Strand* self_, _In_ Message* msg)
1096              {
1097                  Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1098                  DEBUG_ASSERT( NULL != self_ );
1099                  trace_HttpSocketPosting(&self->strand.info.interaction, self->strand.info.interaction.other);
1100              
1101                  // Preserve the message in case there is an error while writing it to the socket during
1102                  // non-IO thread calls to Selector_CallInIOThread.
1103                  // A ref to the message is held until the message is ACK'd.
1104                  DEBUG_ASSERT( NULL == self->savedSendMsg );
1105                  Message_AddRef(msg);
1106                  self->savedSendMsg = msg;
1107                  
1108                  if( MI_RESULT_OK != Selector_CallInIOThread(
1109                      self->http->selector, _SendIN_IO_thread_HttpSocket, self, msg ) )
1110 krisbash 1.3     {
1111                      // We also need to release the page (if any)
1112                      HttpResponseMsg * response = (HttpResponseMsg *)msg;
1113                      DEBUG_ASSERT( HttpResponseMsgTag == msg->tag );
1114                      
1115                      trace_HttpSocket_CannotPostMessage( self, msg, &self->strand.info.interaction, self->strand.info.interaction.other );
1116              
1117                      HttpResponseMsg_Release( response );  // same message as savedSendMsg
1118                      self->savedSendMsg = NULL;
1119                      Strand_ScheduleAck( &self->strand );
1120                  }
1121              }
1122              
1123              void _HttpSocket_PostControl( _In_ Strand* self, _In_ Message* msg)
1124              {
1125                  DEBUG_ASSERT( MI_FALSE );  // not used yet
1126              }
1127              
1128              void _HttpSocket_Ack( _In_ Strand* self)
1129              {
1130                  trace_HttpSocketAck( &self->info.interaction, self->info.interaction.other );
1131 krisbash 1.3     // No need to do anything for now
1132              }
1133              
1134              void _HttpSocket_Cancel( _In_ Strand* self)
1135              {
1136                  // no need to do anything here (upper layer should send proper error response)
1137              }
1138              
1139              void _HttpSocket_Finish( _In_ Strand* self_)
1140              {
1141                  Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1142                  DEBUG_ASSERT( NULL != self_ );
1143                  
1144                  trace_HttpSocketFinish( self_ );
1145                  Strand_Delete( &self->strand );
1146              }
1147              
1148              // HTTPSOCKET_STRANDAUX_NEWREQUEST
1149              void _HttpSocket_Aux_NewRequest( _In_ Strand* self_)
1150              {
1151                  Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
1152 krisbash 1.3     HttpRequestMsg* msg;
1153              
1154                  DEBUG_ASSERT( NULL != self_ );
1155                  msg = self->request;
1156                  DEBUG_ASSERT( NULL != msg );
1157                  
1158                  trace_HttpSocketAuxNewRequest( self, msg );
1159                  self->request = NULL;
1160              
1161                  if( !self_->info.thisClosedOther )
1162                  {
1163                      // Leave the strand for the case where the new request provider 
1164                      // is in-proc and takes over the thread
1165                      Strand_PostAndLeaveStrand( &self->strand, &msg->base );
1166                  }
1167              
1168                  HttpRequestMsg_Release( msg );
1169              }
1170              
1171              /*
1172                  Object that implements the HTTP protocol endpoint on a TCP Socket.
1173 krisbash 1.3     Usually connects to WSMAN interaction object.
1174              
1175                  Behaviour:
1176                  - Post tries to schedule the operation on the IO thread (thru selector)
1177                     if that fails it sends the Ack immediately. Note that the response message 
1178                     is delivered from WSMAN inside a HttpResponseMsg
1179                  - Post control is not implemented
1180                  - Both Cancel, Close and Ack do nothing (in case of cancelation upper layer should
1181                     send an actual response)
1182                  - Shutdown: 
1183                     Once the connection is closed by the client that is notified to _RequestCallback
1184                     which calls Strand_ScheduleClose on component to the right.
1185                     From there normal Strand logic applies: once the upper layer 
1186                     also closes the interaction the object is deleted.
1187              
1188                  Unique features and special Behavour:
1189                  - When a complete message has been read instead of scheduling a post
1190                     the auxiliary function HTTPSOCKET_STRANDAUX_NEWREQUEST is 
1191                     scheduled instead. That function takes care of posting using 
1192                     Strand_PostAndLeaveStrand (which avoids holding the strand in case the thread 
1193                     is going to be hijacked  by the provider in the processing of that post).
1194 krisbash 1.3 */
1195              static StrandFT _HttpSocket_FT = { 
1196                  _HttpSocket_Post, 
1197                  _HttpSocket_PostControl, 
1198                  _HttpSocket_Ack, 
1199                  _HttpSocket_Cancel, 
1200                  NULL,
1201                  _HttpSocket_Finish,
1202                  NULL,
1203                  _HttpSocket_Aux_NewRequest,
1204                  NULL,
1205                  NULL,
1206                  NULL,
1207                  NULL };
1208              
1209              /*
1210              **==============================================================================
1211              */
1212                  
1213 mike     1.1 static MI_Boolean _ListenerCallback(
1214                  Selector* sel,
1215                  Handler* handler_,
1216                  MI_Uint32 mask, 
1217                  MI_Uint64 currentTimeUsec)
1218              {
1219                  Http_Listener_SocketData* handler = (Http_Listener_SocketData*)handler_;
1220                  Http* self = (Http*)handler->base.data;
1221                  MI_Result r;
1222                  Sock s;
1223                  Addr addr;
1224                  Http_SR_SocketData* h;
1225              
1226                  sel=sel;
1227                  mask=mask;
1228                  currentTimeUsec = currentTimeUsec;
1229              
1230                  if (mask & SELECTOR_READ)
1231                  {
1232                      int count;
1233              
1234 mike     1.1         for (count = 0; count < 5; count++)
1235                      {
1236                          /* Accept the incoming connection */
1237                          r = Sock_Accept(handler->base.sock, &s, &addr);
1238              
1239                          if (MI_RESULT_WOULD_BLOCK == r)
1240                              return MI_TRUE;
1241              
1242              
1243                          if (r != MI_RESULT_OK)
1244                          {
1245 krisbash 1.3                 trace_SockAccept_Failed(Sock_GetLastError());
1246 mike     1.1                 return MI_TRUE;
1247                          }
1248              
1249                          r = Sock_SetBlocking(s, MI_FALSE);
1250                          if (r != MI_RESULT_OK)
1251                          {
1252 krisbash 1.3                 trace_SockSetBlocking_Failed();
1253 mike     1.1                 Sock_Close(s);
1254                              return MI_TRUE;
1255                          }
1256              
1257                          /* Create handler */
1258 krisbash 1.3             h = (Http_SR_SocketData*)Strand_New( STRAND_DEBUG( HttpSocket ) &_HttpSocket_FT, sizeof(Http_SR_SocketData), STRAND_FLAG_ENTERSTRAND, NULL );
1259 mike     1.1 
1260                          if (!h)
1261                          {
1262 krisbash 1.3                 trace_SocketClose_Http_SR_SocketDataAllocFailed();
1263 mike     1.1                 Sock_Close(s);
1264                              return MI_TRUE;
1265                          }
1266              
1267 krisbash 1.3             h->http = self;
1268 mike     1.1             h->recvBufferSize = INITIAL_BUFFER_SIZE;
1269 krisbash 1.3             h->recvBuffer = (char*)PAL_Calloc(1, h->recvBufferSize);
1270 mike     1.1             if (!h->recvBuffer)
1271                          {
1272 krisbash 1.3                 Strand_Delete(&h->strand);
1273                              trace_SocketClose_recvBuffer_AllocFailed();
1274 mike     1.1                 Sock_Close(s);
1275                              return MI_TRUE;
1276                          }
1277              
1278 krisbash 1.3             h->handler.sock = s;
1279                          h->handler.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1280                          h->handler.callback = _RequestCallback;
1281                          h->handler.data = self;
1282                          h->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
1283 mike     1.1             h->enableTracing = self->options.enableTracing;
1284              
1285                          /* ssl support */
1286                          if (handler->secure)
1287                          {
1288                              h->ssl = SSL_new(self->sslContext);
1289              
1290                              if (!h->ssl)
1291                              {
1292 krisbash 1.3                     trace_SSLNew_Failed();
1293                                  Strand_Delete(&h->strand);
1294 mike     1.1                     Sock_Close(s);
1295                                  return MI_TRUE;
1296                              }
1297              
1298                              if (!(SSL_set_fd(h->ssl, s) ))
1299                              {
1300 krisbash 1.3                     trace_SSL_setfd_Failed();
1301 mike     1.1                     SSL_free(h->ssl);
1302 krisbash 1.3                     Strand_Delete(&h->strand);
1303 mike     1.1                     Sock_Close(s);
1304                                  return MI_TRUE;
1305                              }
1306              
1307                          }
1308              
1309                          /* Watch for read events on the incoming connection */
1310 krisbash 1.3             r = Selector_AddHandler(self->selector, &h->handler);
1311 mike     1.1 
1312                          if (r != MI_RESULT_OK)
1313                          {
1314 krisbash 1.3                 trace_SelectorAddHandler_Failed();
1315 mike     1.1                 if (handler->secure)
1316                                  SSL_free(h->ssl);
1317 krisbash 1.3                 Strand_Delete(&h->strand);
1318 mike     1.1                 Sock_Close(s);
1319                              return MI_TRUE;
1320                          }
1321              
1322 krisbash 1.3             // notify next stack layer about new connection 
1323                          // (open the interaction)
1324                          Strand_Open( 
1325                              &h->strand, 
1326                              self->callbackOnNewConnection,
1327                              self->callbackData,
1328                              NULL,
1329                              MI_TRUE );
1330 mike     1.1         }
1331                  }
1332              
1333                  if ((mask & SELECTOR_REMOVE) != 0 ||
1334                      (mask & SELECTOR_DESTROY) != 0)
1335                  {
1336 krisbash 1.3         trace_SocketClose_REMOVEDESTROY();
1337 mike     1.1         Sock_Close(handler->base.sock);
1338 krisbash 1.3         PAL_Free(handler);
1339 mike     1.1     }
1340              
1341                  return MI_TRUE;
1342              }
1343              
1344              static MI_Result _New_Http(
1345 krisbash 1.3     _Out_       Http**              selfOut,
1346                  _In_        Selector*           selector, /*optional, maybe NULL*/
1347                  _In_        OpenCallback        callbackOnNewConnection,
1348                  _In_opt_    void*               callbackData)
1349 mike     1.1 {
1350                  Http* self;
1351              
1352                  /* Check parameters */
1353                  if (!selfOut)
1354                      return MI_RESULT_INVALID_PARAMETER;
1355              
1356                  /* Clear output parameter */
1357                  *selfOut = NULL;
1358              
1359                  /* Allocate structure */
1360                  {
1361 krisbash 1.3         self = (Http*)PAL_Calloc(1, sizeof(Http));
1362 mike     1.1 
1363                      if (!self)
1364                          return MI_RESULT_FAILED;
1365                  }
1366              
1367                  if (selector)
1368                  {   /* attach the exisiting selector */
1369                      self->selector = selector;
1370                      self->internalSelectorUsed = MI_FALSE;
1371                  }
1372                  else
1373                  {   /* creaet a new selector */
1374                      /* Initialize the network */
1375                      Sock_Start();
1376              
1377                      /* Initialize the selector */
1378                      if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1379                      {
1380 krisbash 1.3             PAL_Free(self);
1381 mike     1.1             return MI_RESULT_FAILED;
1382                      }
1383                      self->selector = &self->internalSelector;
1384                      self->internalSelectorUsed = MI_TRUE;
1385                  }
1386              
1387                  /* Save the callback and callbackData */
1388                  self->callbackOnNewConnection = callbackOnNewConnection;
1389                  self->callbackData = callbackData;
1390              
1391                  /* Set the magic number */
1392                  self->magic = _MAGIC;
1393              
1394                  /* Set output parameter */
1395                  *selfOut = self;
1396                  return MI_RESULT_OK;
1397              }
1398              
1399              #ifdef CONFIG_POSIX
1400              static MI_Boolean _verifyPrivateKey(
1401                  SSL_CTX *ctx, 
1402 mike     1.1     const char* keyPath)
1403              {
1404                  // Open the private key file.
1405              
1406                  FILE* is = fopen(keyPath, "r");
1407              
1408                  if (!is)
1409                  {
1410 krisbash 1.3         trace_SSL_FailedToOpenPrivateKeyFile(scs(keyPath));
1411 mike     1.1         return MI_FALSE;
1412                  }
1413              
1414                  // Read the private key from the input stream.
1415              
1416                  EVP_PKEY* pkey;
1417                  pkey = PEM_read_PrivateKey(is, NULL, NULL, NULL);
1418              
1419                  if (!pkey)
1420                  {
1421 krisbash 1.3         trace_SSL_FailedToCreatePrivateKey();
1422 mike     1.1         return MI_FALSE;
1423                  }
1424              
1425                  /* Close the input stream. */
1426              
1427                  fclose(is);
1428              
1429                  /* Associate the new private key with the SSL context object. */
1430              
1431                  if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
1432                  {
1433                      EVP_PKEY_free(pkey);
1434 krisbash 1.3         trace_SSL_NoPrivateKeyFound(scs(keyPath));
1435 mike     1.1         return MI_FALSE;
1436                  }
1437              
1438                  EVP_PKEY_free(pkey);
1439              
1440                  /* Check private key for validity. */
1441              
1442                  if (!SSL_CTX_check_private_key(ctx))
1443                  {
1444 krisbash 1.3         trace_SSL_PrivateAndPublicKeyDonotMatch();
1445 mike     1.1         return MI_FALSE;
1446                  }
1447              
1448                  return MI_TRUE;
1449              }
1450              
1451 krisbash 1.3 static MI_Result _CreateSSLContext(Http* self, const char* sslCipherSuite, Server_SSL_Options sslOptions)
1452 mike     1.1 {
1453 krisbash 1.3     SSL_CTX* sslContext = 0;
1454                  long options = 0;
1455 mike     1.1 
1456                  sslContext = SSL_CTX_new(SSLv23_method());
1457              
1458                  if (!sslContext)
1459                  {
1460 krisbash 1.3         trace_SSL_CannotCreateContext();
1461 mike     1.1         return MI_RESULT_FAILED;
1462                  }
1463 krisbash 1.3 
1464                  if (sslCipherSuite != NULL)
1465                  {
1466                      // Set the cipher list to the user specified cipher list.
1467                      if (SSL_CTX_set_cipher_list(sslContext, sslCipherSuite) == 0)
1468                      {
1469                          trace_SSL_BadCipherList(scs(sslCipherSuite));
1470                          return MI_RESULT_FAILED;
1471                      }
1472                  }
1473              
1474                  // Disable SSL_v2 and/or SSL_v3 if requested
1475                  if ( sslOptions & DISABLE_SSL_V2 )
1476                  {
1477                      options |= SSL_OP_NO_SSLv2;
1478                  }
1479                  if ( sslOptions & DISABLE_SSL_V3 )
1480                  {
1481                      options |= SSL_OP_NO_SSLv3;
1482                  }
1483                  if ( SSL_CTX_set_options(sslContext, options) == 0 )
1484 krisbash 1.3     {
1485                      trace_SSL_CannotSetOptions( options );
1486                      return MI_RESULT_FAILED;
1487                  }
1488              
1489 mike     1.1     SSL_CTX_set_quiet_shutdown(sslContext, 1);
1490                  SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
1491                  SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
1492                  SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
1493              
1494                  /* Check if there is a certificate file (file containing server
1495                  ** certificate) specified. If specified, validate and load the
1496                  ** certificate.
1497                  */
1498                  {
1499 krisbash 1.3         char errorBuf[256];
1500              
1501 mike     1.1         /* load the specified server certificates */
1502 krisbash 1.3         trace_SSL_LoadingServerCert(scs(OMI_GetPath(ID_PEMFILE)));
1503 mike     1.1 
1504                      if (SSL_CTX_use_certificate_file(sslContext,
1505 krisbash 1.3             OMI_GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)
1506 mike     1.1         {
1507 krisbash 1.3             trace_SSL_NoServerCertFound(OMI_GetPath(ID_PEMFILE), GetSslErrorString(errorBuf, 256));
1508 mike     1.1             SSL_CTX_free(sslContext);
1509                          return MI_RESULT_FAILED;
1510                      }
1511                  }
1512              
1513                  /*
1514                  ** Check if there is a key file (file containing server
1515                  ** private key) specified and the key was not already loaded.
1516                  ** If specified, validate and load the key.
1517                  */
1518                  {
1519 krisbash 1.3         char errorBuf[256];
1520              
1521 mike     1.1         /* load the specified server certificates */
1522 krisbash 1.3         trace_SSL_LoadingCertPrivateKey(scs(OMI_GetPath(ID_KEYFILE)));
1523 mike     1.1 
1524 krisbash 1.3         /* load given private key and check for validity
1525                      */
1526                      if (!_verifyPrivateKey(sslContext, OMI_GetPath(ID_KEYFILE)))
1527                      {
1528                          trace_SSL_NoServerCertFound(scs(OMI_GetPath(ID_KEYFILE)), GetSslErrorString(errorBuf, sizeof errorBuf));
1529 mike     1.1             SSL_CTX_free(sslContext);
1530                          return MI_RESULT_FAILED;
1531                      }
1532                  }
1533              
1534                  self->sslContext = sslContext;
1535                  return MI_RESULT_OK;
1536              }
1537              #endif
1538              
1539              static MI_Result _CreateAddListenerSocket(
1540                  Http* self,
1541                  unsigned short port,
1542                  MI_Boolean  secure
1543                  )
1544              {
1545                  Addr addr;
1546                  Sock listener;
1547                  MI_Result r;
1548              
1549                  /* Create listener socket */
1550 mike     1.1     {
1551                      Addr_InitAny(&addr, port);
1552                      r = Sock_CreateListener(&listener, &addr);
1553              
1554                      if (r != MI_RESULT_OK)
1555                      {
1556                          return r;
1557                      }
1558              
1559                      r = Sock_SetBlocking(listener, MI_FALSE);
1560              
1561                      if (r != MI_RESULT_OK)
1562                      {
1563 krisbash 1.3             trace_SocketClose_SetBlockingFailed();
1564 mike     1.1             Sock_Close(listener);
1565                          return r;
1566                      }
1567                  }
1568              
1569                  /* Watch for read events on the listener socket (client connections) */
1570                  {
1571 krisbash 1.3         Http_Listener_SocketData* h = (Http_Listener_SocketData*)PAL_Calloc(1, sizeof(Http_Listener_SocketData));
1572 mike     1.1 
1573                      if (!h)
1574                      {
1575 krisbash 1.3             trace_SocketClose_Http_Listener_SocketDataAllocFailed();
1576 mike     1.1             Sock_Close(listener);
1577                          return MI_RESULT_FAILED;
1578                      }
1579              
1580                      h->base.sock = listener;
1581                      h->base.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
1582                      h->base.callback = _ListenerCallback;
1583                      h->base.data = self;
1584                      h->secure = secure;
1585              
1586                      r = Selector_AddHandler(self->selector, &h->base);
1587              
1588                      if (r != MI_RESULT_OK)
1589                      {
1590 krisbash 1.3             trace_SocketClose_Selector_AddHandlerFailed();
1591 mike     1.1             Sock_Close(listener);
1592 krisbash 1.3             PAL_Free(h);
1593 mike     1.1             return r;
1594                      }
1595                  }
1596              
1597                  return MI_RESULT_OK;
1598              }
1599              
1600              MI_Result Http_New_Server(
1601 krisbash 1.3     _Out_       Http**              selfOut,
1602                  _In_        Selector*           selector,               /* optional, maybe NULL*/
1603                  _In_        unsigned short      http_port,              /* 0 to disable */
1604                  _In_        unsigned short      https_port,             /* 0 to disable */
1605                  _In_opt_z_  const char*         sslCipherSuite,         /* NULL to disable */
1606                  _In_        Server_SSL_Options  sslOptions,             /* 0 for default options */
1607                  _In_        OpenCallback        callbackOnNewConnection,
1608                  _In_opt_    void*               callbackData,
1609                  _In_opt_    const HttpOptions*  options)
1610 mike     1.1 {
1611                  Http* self;
1612                  MI_Result r;
1613              
1614                  /* allocate this, inits selector */
1615 krisbash 1.3     r = _New_Http(selfOut, selector, callbackOnNewConnection, callbackData);
1616 mike     1.1 
1617                  if (MI_RESULT_OK != r)
1618                      return r;
1619              
1620                  self = *selfOut;
1621              
1622                  /* Create http listener socket */
1623                  if (http_port)
1624                  {
1625                      r = _CreateAddListenerSocket(self, http_port, MI_FALSE);
1626              
1627                      if (r != MI_RESULT_OK)
1628                      {
1629                          Http_Delete(self);
1630                          return r;
1631                      }
1632                  }
1633              
1634              #ifdef CONFIG_POSIX
1635                  /* Create https listener socket */
1636                  if (https_port)
1637 mike     1.1     {
1638                      /* init ssl */
1639                      SSL_library_init();
1640              
1641                      /* create context */
1642 krisbash 1.3         r = _CreateSSLContext(self, sslCipherSuite, sslOptions);
1643 mike     1.1 
1644                      if (r != MI_RESULT_OK)
1645                      {
1646                          Http_Delete(self);
1647                          return r;
1648                      }
1649              
1650                      /* create a socket */
1651                      r = _CreateAddListenerSocket(self, https_port, MI_TRUE);
1652              
1653                      if (r != MI_RESULT_OK)
1654                      {
1655                          Http_Delete(self);
1656                          return r;
1657                      }
1658                  }
1659              #else
1660                  MI_UNUSED(https_port);
1661              #endif
1662              
1663 krisbash 1.3     // options 
1664                  if( NULL == options )
1665                  {
1666                      HttpOptions tmpOptions = DEFAULT_HTTP_OPTIONS;
1667                      self->options = tmpOptions;
1668                  }
1669                  else
1670                  {
1671                      self->options = *options;
1672                  }
1673              
1674 mike     1.1     return MI_RESULT_OK;
1675              }
1676              
1677              MI_Result Http_Delete(
1678                  Http* self)
1679              {
1680                  /* Check parameters */
1681                  if (!self)
1682                      return MI_RESULT_INVALID_PARAMETER;
1683              
1684                  /* Check magic number */
1685                  if (self->magic != _MAGIC)
1686                      return MI_RESULT_INVALID_PARAMETER;
1687              
1688                  if (self->internalSelectorUsed)
1689                  {
1690                      /* Release selector;
1691 krisbash 1.3         Note: selector-destory closes all sockets in a list including connector and listener */
1692 mike     1.1         Selector_Destroy(self->selector);
1693              
1694                      /* Shutdown the network */
1695                      Sock_Stop();
1696                  }
1697              
1698                  if (self->sslContext)
1699                      SSL_CTX_free(self->sslContext);
1700              
1701                  /* Clear magic number */
1702                  self->magic = 0xDDDDDDDD;
1703              
1704                  /* Free self pointer */
1705 krisbash 1.3     PAL_Free(self);
1706 mike     1.1 
1707                  return MI_RESULT_OK;
1708              }
1709              
1710              MI_Result Http_Run(
1711                  Http* self,
1712                  MI_Uint64 timeoutUsec)
1713              {
1714                  /* Run the selector */
1715 krisbash 1.3     return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
1716 mike     1.1 }
1717              

ViewCVS 0.9.2