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

ViewCVS 0.9.2