(file) Return to httpclient.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.3 ** 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.3 ** 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.3 ** 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 "httpclient.h"
  29              #include <sock/addr.h>
  30              #include <sock/sock.h>
  31              #include <sock/selector.h>
  32 krisbash 1.3 #include <pal/sleep.h>
  33 mike     1.1 #include <base/buf.h>
  34              #include <base/log.h>
  35              #include <base/result.h>
  36 krisbash 1.4 #include <pal/intsafe.h>
  37 krisbash 1.3 #include <pal/strings.h>
  38              #include <pal/format.h>
  39              #include <pal/sleep.h>
  40 mike     1.1 #include <base/paths.h>
  41              
  42 krisbash 1.3 // #define ENABLE_TRACING 1
  43              #ifdef ENABLE_TRACING
  44              # define TRACING_LEVEL 4
  45              # include <deprecated/logging/logging.h>
  46              #else
  47              # define LOGE2(a)
  48              # define LOGW2(a)
  49              # define LOGD2(a)
  50              # define LOGX2(a)
  51              #endif
  52              
  53 mike     1.1 #ifdef CONFIG_POSIX
  54              #include <openssl/ssl.h>
  55              #include <openssl/err.h>
  56              #else
  57              /* ssl not supported in this configuration; just make compiler happy */
  58              typedef void SSL;
  59              typedef void SSL_CTX;
  60              #define SSL_CTX_free(c)
  61              #define SSL_new(c) 0
  62              #define SSL_free(c)
  63              #define SSL_set_connect_state(c)
  64              #define SSL_set_fd(c,a) (a==a)
  65              #define SSL_read(c,a,b) 0
  66              #define SSL_write(c,a,b) 0
  67              #define SSL_get_error(c,e) e
  68              #define SSL_ERROR_WANT_WRITE 0
  69              #define SSL_ERROR_WANT_READ 1
  70              #define SSL_ERROR_SYSCALL 2
  71              
  72              #ifdef EWOULDBLOCK
  73              # undef EWOULDBLOCK
  74 mike     1.1 #endif
  75              
  76              #define EWOULDBLOCK 0
  77              
  78              #ifdef EINPROGRESS
  79              # undef EINPROGRESS
  80 krisbash 1.3 #endif
  81 mike     1.1 
  82              #define EINPROGRESS 0
  83              
  84              #define ERR_get_error() 0
  85              #define ERR_error_string_n(c,a,b) a[0]=0
  86              #define SSL_accept(c) 0
  87              #define SSL_connect(c) 0
  88              
  89              #endif
  90              
  91              /*
  92              **==============================================================================
  93              **
  94              ** Local definitions:
  95              **
  96              **==============================================================================
  97              */
  98              
  99              static const MI_Uint32 _MAGIC = 0x5FC7B966;
 100              static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
 101              static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
 102 mike     1.1 static const MI_Uint32 DEFAULT_HTTP_TIMEOUT_USEC = 60 * 1000000;
 103              
 104              typedef enum _Http_RecvState
 105              {
 106                  RECV_STATE_HEADER,
 107                  RECV_STATE_CONTENT,
 108                  RECV_STATE_CHUNKHEADER,
 109                  RECV_STATE_CHUNKDATA
 110              }
 111              Http_RecvState;
 112              
 113 krisbash 1.3 typedef struct _HttpClient_SR_SocketData
 114 mike     1.1 {
 115                  /* based member*/
 116                  Handler     base;
 117              
 118                  /* timeout */
 119                  MI_Uint64   timeoutUsec;
 120              
 121                  /* ssl part */
 122                  SSL*  ssl;
 123                  MI_Boolean  reverseOperations;  /*reverse read/write Events/Handlers*/
 124                  MI_Boolean  connectDone;
 125              
 126                  /* receiving data */
 127 krisbash 1.3     __field_ecount(recvBufferSize) char* recvBuffer;
 128 mike     1.1     size_t      recvBufferSize;
 129 krisbash 1.3     size_t      receivedSize;
 130 mike     1.1     Http_RecvState      recvingState;
 131                  HttpClientHeaderField recvHeaderFields[64];
 132                  HttpClientResponseHeader   recvHeaders;
 133                  MI_Sint64   contentLength;
 134 krisbash 1.3     MI_Sint64   contentBegin;
 135                  MI_Sint64   contentEnd;
 136                  MI_Sint64   contentTotalLength;
 137 mike     1.1     Page*   recvPage;
 138              
 139 krisbash 1.3     /* flag for a response from a HEAD request */
 140                  MI_Boolean  headVerb;
 141              
 142 mike     1.1     /* sending part */
 143                  Page*   sendPage;
 144                  Page*   sendHeader;
 145                  size_t      sentSize;
 146                  Http_RecvState  sendingState;
 147              
 148                  /* general operation status */
 149                  MI_Result status;
 150              
 151              }
 152 krisbash 1.3 HttpClient_SR_SocketData;
 153 mike     1.1 
 154              struct _HttpClient
 155              {
 156                  MI_Uint32       magic;
 157                  Selector        internalSelector;
 158                  Selector*       selector;
 159                  HttpClientCallbackOnStatus     callbackOnStatus;
 160                  HttpClientCallbackOnResponse   callbackOnResponse;
 161                  void*                               callbackData;
 162                  SSL_CTX*    sslContext;
 163              
 164 krisbash 1.3     HttpClient_SR_SocketData* connector;
 165 mike     1.1 
 166                  MI_Boolean  internalSelectorUsed;
 167              };
 168              
 169              
 170              /* helper functions result */
 171              typedef enum _Http_CallbackResult
 172              {
 173 krisbash 1.3     PRT_RETURN_FALSE,
 174 mike     1.1     PRT_RETURN_TRUE,
 175 krisbash 1.3     PRT_CONTINUE
 176 mike     1.1 }
 177              Http_CallbackResult;
 178              
 179              
 180              MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
 181              {
 182                  return (MI_Uint8)tolower(x);
 183              }
 184              
 185              #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8)  | (((MI_Uint16)len)) )
 186              
 187 krisbash 1.3 _Return_type_success_(return == MI_TRUE)
 188 mike     1.1 static MI_Boolean _getNameValuePair(
 189 krisbash 1.3     _Inout_ CharPtr* line,
 190                  _Out_ CharPtr* value,
 191                  _Out_ int*  nameHashCode)
 192 mike     1.1 {
 193                  int len = 0;
 194                  char* p;
 195                  /* find name end /hash-code */
 196              
 197 krisbash 1.3     if ((*line)[0] == '\0')
 198                  {
 199                      return MI_FALSE;
 200                  }
 201              
 202 mike     1.1     *nameHashCode =  _ToLower((MI_Uint8)(*line)[0])<<16;
 203              
 204 krisbash 1.3     for (len = 1; (*line)[len] != '\0' && (*line)[len] != ':' && (*line)[len] != '\r'; len++)
 205 mike     1.1         ;
 206              
 207                  if ((*line)[len] != ':')
 208                      return MI_FALSE;
 209              
 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.3         if (p[0] != '\0' && p[1] != '\0' && p[2] != '\0' &&
 224                          p[0] == '\r' && p[1] == '\n' &&
 225                          p[2] != ' '  && p[2] != '\t')
 226 mike     1.1         {
 227 krisbash 1.3             p[0] = '\0';
 228 mike     1.1             (*line) = p + 2;
 229                          break;
 230                      }
 231 krisbash 1.3         p++;
 232 mike     1.1     }
 233              
 234                  /* remove trailing spaces */
 235                  p--;
 236 krisbash 1.3 #ifdef _PREFAST_
 237              #pragma prefast (push)
 238              #pragma prefast (disable: 26001)
 239              #endif
 240                  /* disabling IPv6 OACR warnings - D3M bug 56 */
 241 mike     1.1     while (p[0] == ' ' || p[0] == '\t')
 242                      p--;
 243 krisbash 1.3 #ifdef _PREFAST_
 244              #pragma prefast (pop)
 245              #endif
 246 mike     1.1 
 247 krisbash 1.3     p[1] = '\0';
 248 mike     1.1 
 249                  return MI_TRUE;
 250              }
 251              
 252              static MI_Boolean _getHeaderField(
 253 krisbash 1.3     HttpClient_SR_SocketData* handler,
 254                  _Inout_ CharPtr* line)
 255 mike     1.1 {
 256                  /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 257                      Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
 258                  */
 259                  char* name = *line;
 260                  char* value = NULL;
 261                  int nameHashCode;
 262              
 263                  if (!_getNameValuePair(line, &value, &nameHashCode))
 264                      return MI_FALSE;
 265              
 266 krisbash 1.3     if (nameHashCode == _HashCode('c', 'h', 14) && /*Content-Length*/
 267 mike     1.1         Strcasecmp(name,"Content-Length") == 0)
 268                  {
 269 krisbash 1.3         handler->contentLength = Strtoull(value, NULL, 10);
 270                      /*if (handler->contentLength > HTTP_MAX_CONTENT)
 271                      handler->contentBegin = -1;
 272                      handler->contentEnd = -1;
 273                      handler->contentTotalLength = -1;
 274                      return MI_FALSE;*/
 275 mike     1.1     }
 276 krisbash 1.3     else if (nameHashCode == _HashCode('t', 'g', 17) && /*Transfer-Encoding*/
 277 mike     1.1         Strcasecmp(name,"Transfer-Encoding") == 0)
 278                  {
 279 krisbash 1.3         handler->contentLength = -1;
 280                      handler->contentBegin = -1;
 281                      handler->contentEnd = -1;
 282                      handler->contentTotalLength = -1;
 283                  }
 284                  else if (nameHashCode == _HashCode('c','e',13) && /*Content-Range*/
 285                      Strcasecmp(name, "Content-Range") == 0)
 286                  {
 287                      char* delimptr;
 288                      char* endptr;
 289                      handler->contentEnd = -1;
 290                      handler->contentBegin = (MI_Sint64)Strtoull(value, NULL, 10);
 291                      delimptr = strchr(value, '-');
 292                      endptr = strchr(value, '\n');
 293                      if (delimptr != NULL && (endptr == NULL || endptr > delimptr))
 294                          handler->contentEnd = Strtoull(++delimptr, NULL, 10);
 295                      delimptr = strchr(value, '/');
 296                      if (delimptr != NULL && (endptr == NULL || endptr > delimptr))
 297                          handler->contentTotalLength = Strtoull(++delimptr, NULL, 10);
 298                  }
 299                  if (handler->recvHeaders.sizeHeaders < MI_COUNT(handler->recvHeaderFields))
 300 krisbash 1.3     {
 301                      handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].name = name;
 302                      handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].value = value;
 303                      handler->recvHeaders.sizeHeaders++;
 304 mike     1.1     }
 305                  else
 306                  {
 307 krisbash 1.3         trace_TooManyHttpHeaders(scs(name), scs(value));
 308 mike     1.1     }
 309              
 310                  return MI_TRUE;
 311              }
 312              
 313              static MI_Boolean _getChunkSize(
 314                  const char * line,
 315                  MI_Uint32* chunkSize)
 316              {
 317                  *chunkSize = 0;
 318              
 319 krisbash 1.3     while (*line)
 320 mike     1.1     {
 321                      char c = *line;
 322              
 323                      if (c >= '0' && c <= '9')
 324                          *chunkSize = *chunkSize * 16 + (c - '0');
 325                      else if (c >= 'a' && c <= 'f')
 326                          *chunkSize = *chunkSize * 16 + (c - 'a' + 10);
 327                      else if (c >= 'A' && c <= 'F')
 328                          *chunkSize = *chunkSize * 16 + (c - 'A' + 10);
 329                      else
 330                          break;
 331              
 332                      line++;
 333                  }
 334              
 335                  return MI_TRUE;
 336              }
 337              
 338              
 339              static MI_Boolean _getRequestLine(
 340 krisbash 1.3     HttpClient_SR_SocketData* handler,
 341                  _Inout_ CharPtr* line)
 342 mike     1.1 {
 343                  size_t index;
 344                  /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 345                      Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
 346                  */
 347              
 348                  /* initialize header */
 349                  handler->recvHeaders.sizeHeaders = 0;
 350                  handler->recvHeaders.headers = handler->recvHeaderFields;
 351              
 352                  /* find http code */
 353                  {
 354                      /* skip http version, that is in format
 355                              HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
 356                              http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1
 357              
 358                              Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 359                      */
 360 krisbash 1.3         const char* s = *line; /*+ HTTP/1.1<sp>*/
 361                      size_t skips = 9;
 362                      for (; skips > 0; s++)
 363                      {
 364                          skips--;
 365                          if (!*s)
 366                          {
 367                              return MI_FALSE;
 368                          }
 369                      }
 370 mike     1.1 
 371                      handler->recvHeaders.httpError = Strtoul(s, NULL, 10);
 372                  }
 373              
 374                  /* skip to end of line */
 375 krisbash 1.3     for (index = 1; (*line)[index] && index < handler->receivedSize; index++)
 376 mike     1.1     {
 377 krisbash 1.3         if ((*line)[index-1] == '\r' && (*line)[index] == '\n')
 378 mike     1.1         {
 379                          (*line) = (*line) + index + 1;
 380                          return MI_TRUE;
 381                      }
 382                  }
 383              
 384                  return MI_FALSE;
 385              }
 386              
 387              static MI_Result _Sock_Read(
 388 krisbash 1.3     HttpClient_SR_SocketData* handler,
 389 mike     1.1     void* buf,
 390                  size_t buf_size,
 391                  size_t* sizeRead)
 392              {
 393                  int res;
 394 krisbash 1.3     int sslError;
 395              
 396                  if (handler->ssl == NULL)
 397                  {
 398                      MI_Result res = Sock_Read(handler->base.sock, buf, buf_size, sizeRead);
 399 mike     1.1 
 400 krisbash 1.3         LOGD2((ZT("_Sock_Read - After regular read. socket: %d, result: %d (%s), bytes read: %u / %u"), handler->base.sock, (int)res, mistrerror(res), (unsigned int)*sizeRead, (unsigned int)buf_size));
 401                      return res;
 402                  }
 403 mike     1.1 
 404                  handler->base.mask &= ~SELECTOR_WRITE;
 405                  handler->base.mask |= SELECTOR_READ;
 406                  handler->reverseOperations = MI_FALSE;
 407              
 408                  *sizeRead = 0;
 409              
 410                  res = SSL_read(handler->ssl, buf, buf_size);
 411 krisbash 1.3     LOGD2((ZT("_Sock_Read - SSL_Read returned: %d (< 0 for error) / %u bytes read, errno: %d (%s)"), res, (unsigned int)buf_size, errno, strerror(errno)));
 412                  if (res == 0)
 413                  {
 414                      LOGW2((ZT("_Sock_Read - SSL socket connection closed. socket: %d"), handler->base.sock));
 415 mike     1.1         return MI_RESULT_OK;    /* connection closed */
 416 krisbash 1.3     }
 417 mike     1.1 
 418 krisbash 1.3     if (res > 0)
 419 mike     1.1     {
 420 krisbash 1.3         LOGD2((ZT("_Sock_read - Bytes read: %d"), res));
 421 mike     1.1         *sizeRead = res;
 422                      return MI_RESULT_OK;    /* ok */
 423                  }
 424              
 425 krisbash 1.3     sslError = SSL_get_error(handler->ssl, res);
 426                  switch (sslError)
 427 mike     1.1     {
 428                  case SSL_ERROR_WANT_WRITE:
 429                      handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 430                      handler->base.mask &= ~SELECTOR_READ;
 431                      handler->base.mask |= SELECTOR_WRITE;
 432 krisbash 1.3         LOGD2((ZT("_Sock_Read - SSL_read/accept returned WANT_WRITE")));
 433 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 434              
 435                  case SSL_ERROR_WANT_READ:
 436 krisbash 1.3         LOGD2((ZT("Sock_Read - SSL_read/accept returned WANT_READ")));
 437 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 438              
 439                  case SSL_ERROR_SYSCALL:
 440                      if (EAGAIN == errno ||
 441                          EWOULDBLOCK == errno ||
 442                          EINPROGRESS == errno)
 443                          return MI_RESULT_WOULD_BLOCK;
 444              
 445 krisbash 1.3         LOGE2((ZT("Sock_Read - SSL_read returned OS error %d (%s)"), errno, strerror(errno)));
 446                      trace_SSLRead_UnexpectedSysError(errno);
 447 mike     1.1         break;
 448              
 449                  default:
 450 krisbash 1.3         /* print Open SSL error stack */
 451 mike     1.1         {
 452 krisbash 1.3             unsigned long err;
 453                          while ((err = ERR_get_error()) != 0)
 454 mike     1.1             {
 455                              char err_txt[200];
 456              
 457 krisbash 1.3                 ERR_error_string_n(err, err_txt, sizeof (err_txt));
 458                              LOGE2((ZT("_Sock_Read - SSL_read returned OpenSSL error: %lu (%s)"), err, err_txt));
 459 mike     1.1             }
 460                      }
 461                      break;
 462                  }
 463                  return MI_RESULT_FAILED;
 464              }
 465              
 466              static MI_Result _Sock_Write(
 467 krisbash 1.3     HttpClient_SR_SocketData* handler,
 468 mike     1.1     void* buf,
 469                  size_t buf_size,
 470                  size_t* sizeWritten)
 471              {
 472                  int res;
 473 krisbash 1.3     int sslError;
 474 mike     1.1 
 475                  if (!handler->ssl)
 476 krisbash 1.3     {
 477                      MI_Result res = Sock_Write(handler->base.sock, buf, buf_size, sizeWritten);
 478                      LOGD2((ZT("_Sock_Write - Non-SSS write. Sock_Write returned %d (%s). %u / %u bytes sent"), res, mistrerror(res), (unsigned int)*sizeWritten, (unsigned int)buf_size));
 479                      return res;
 480                  }
 481 mike     1.1 
 482                  /* Do not clear READ flag, since 'close' notification
 483 krisbash 1.3        delivered as READ event */
 484 krisbash 1.4     handler->base.mask &= ~SELECTOR_READ;
 485 mike     1.1     handler->base.mask |= SELECTOR_WRITE;
 486                  handler->reverseOperations = MI_FALSE;
 487              
 488                  *sizeWritten = 0;
 489              
 490                  if (handler->connectDone)
 491                  {
 492                      res = SSL_write(handler->ssl, buf, buf_size);
 493 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL_write using socket %d returned %d (< 0 for error) / %u bytes written, errno: %d (%s)"), handler->base.sock, res, (unsigned int)buf_size, errno, strerror(errno)));
 494 mike     1.1     }
 495                  else
 496                  {
 497                      res = SSL_connect(handler->ssl);
 498 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL connect using socket %d returned result: %d, errno: %d (%s)"), handler->base.sock, res, errno, strerror(errno)));
 499                      if (res > 0)
 500 mike     1.1         {
 501 krisbash 1.3             /* we are done with accept */
 502 mike     1.1             handler->connectDone = MI_TRUE;
 503                          return _Sock_Write(handler,buf,buf_size,sizeWritten);
 504                      }
 505                      /* perform regular error checking */
 506                  }
 507              
 508              
 509 krisbash 1.3     if (res == 0)
 510                  {
 511                      LOGW2((ZT("_Sock_Write - SSL socket connection closed")));
 512 mike     1.1         return MI_RESULT_OK;    /* connection closed */
 513 krisbash 1.3     }
 514 mike     1.1 
 515 krisbash 1.3     if (res > 0)
 516 mike     1.1     {
 517                      *sizeWritten = res;
 518 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL socket successful write of %d / %u bytes"), res, (unsigned int)buf_size));
 519 mike     1.1         return MI_RESULT_OK;    /* ok */
 520                  }
 521              
 522 krisbash 1.3     sslError = SSL_get_error(handler->ssl, res);
 523                  switch (sslError)
 524 mike     1.1     {
 525                  case SSL_ERROR_WANT_WRITE:
 526 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL_write/connect returned WANT_WRITE")));
 527 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 528              
 529                  case SSL_ERROR_WANT_READ:
 530 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL_write/connect returned WANT_READ")));
 531 mike     1.1         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 532                      handler->base.mask |= SELECTOR_READ;
 533 krisbash 1.4         handler->base.mask &= ~SELECTOR_WRITE;
 534 mike     1.1         return MI_RESULT_WOULD_BLOCK;
 535              
 536                  case SSL_ERROR_SYSCALL:
 537                      if (EAGAIN == errno ||
 538                          EWOULDBLOCK == errno ||
 539                          EINPROGRESS == errno)
 540 krisbash 1.3         {
 541                          LOGD2((ZT("_Sock_Write - Returning WOULD_BLOCK. errno: %d (%s)"), errno, strerror(errno)));
 542 mike     1.1             return MI_RESULT_WOULD_BLOCK;
 543 krisbash 1.3         }
 544              
 545                      LOGE2((ZT("_Sock_Write - SSL_write/connect returned unexpected OS error %d (%s)"), errno, strerror(errno)));
 546                      trace_SSLWrite_UnexpectedSysError(errno);
 547                      break;
 548 mike     1.1 
 549 krisbash 1.3     case SSL_ERROR_SSL:
 550                      LOGE2((ZT("_Sock_Write - SSL_write/connect returned OpenSSL error %d (%s)"), sslError, ERR_error_string(sslError, NULL)));
 551 mike     1.1         break;
 552              
 553                  default:
 554 krisbash 1.3         LOGD2((ZT("_Sock_Write - SSL_write/connect returned uncategorized OpenSSL error: %d"), res));
 555 mike     1.1         break;
 556                  }
 557 krisbash 1.3 
 558 mike     1.1     return MI_RESULT_FAILED;
 559              }
 560              
 561              static Http_CallbackResult _ReadHeader(
 562 krisbash 1.3     HttpClient_SR_SocketData* handler)
 563 mike     1.1 {
 564                  char* buf;
 565                  char* currentLine;
 566                  char* data;
 567 krisbash 1.3     size_t contentSize;
 568 mike     1.1     size_t buf_size, received, index;
 569                  MI_Result r;
 570                  MI_Boolean fullHeaderReceived = MI_FALSE;
 571              
 572                  /* are we done with header? */
 573                  if (handler->recvingState != RECV_STATE_HEADER)
 574                      return PRT_CONTINUE;
 575              
 576 krisbash 1.3     buf = handler->recvBuffer + handler->receivedSize;
 577                  buf_size = handler->recvBufferSize - handler->receivedSize;
 578 mike     1.1     received = 0;
 579              
 580                  r = _Sock_Read(handler, buf, buf_size, &received);
 581 krisbash 1.3     LOGD2((ZT("_ReadHeader - Begin. _Sock_read result: %d (%s), socket: %d, %u / %u bytes read, reverse: %d"), (int)r, mistrerror(r), (int)handler->base.sock, (unsigned int)received, (unsigned int)buf_size, (int)handler->reverseOperations));
 582 mike     1.1 
 583 krisbash 1.3     if (r == MI_RESULT_OK && 0 == received)
 584                  {
 585                      LOGW2((ZT("_ReadHeader - 0 bytes received without error. Socket closed?")));
 586                      return PRT_RETURN_FALSE; /* connection closed */
 587                  }
 588 mike     1.1 
 589 krisbash 1.3     if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
 590                  {
 591                      LOGE2((ZT("_ReadHeader - Error %d (%s)"), r, mistrerror(r)));
 592 mike     1.1         return PRT_RETURN_FALSE;
 593 krisbash 1.3     }
 594 mike     1.1 
 595 krisbash 1.3     if (received == 0)
 596                  {
 597                      LOGD2((ZT("_ReadHeader - 0 bytes received. Waiting...")));
 598 mike     1.1         return PRT_RETURN_TRUE;
 599 krisbash 1.3     }
 600 mike     1.1 
 601 krisbash 1.3     handler->receivedSize += received;
 602 mike     1.1 
 603                  /* check header */
 604 krisbash 1.3     LOGD2((ZT("_ReadHeader - Received buffer: %s"), buf));
 605 mike     1.1 
 606                  /* did we get full header? */
 607                  buf = handler->recvBuffer;
 608 krisbash 1.3     LOGD2((ZT("_ReadHeader - Checking for full header...")));
 609                  for ( index = 3; index < handler->receivedSize; index++ )
 610 mike     1.1     {
 611 krisbash 1.3         _Analysis_assume_(handler->recvBufferSize > 3);
 612 mike     1.1         if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
 613                          buf[index-2] == '\n' && buf[index] == '\n' )
 614                      {
 615                          fullHeaderReceived = MI_TRUE;
 616 krisbash 1.3             LOGD2((ZT("_ReadHeader - Full header has been received")));
 617 mike     1.1             break;
 618                      }
 619                  }
 620              
 621 krisbash 1.3     if (!fullHeaderReceived)
 622 mike     1.1     {
 623 krisbash 1.3         if (handler->receivedSize <  handler->recvBufferSize)
 624                      {
 625                          LOGD2((ZT("_ReadHeader - Full header not received. Waiting...")));
 626 mike     1.1             return PRT_RETURN_TRUE; /* continue reading */
 627 krisbash 1.3         }
 628 mike     1.1 
 629 krisbash 1.3         if (handler->recvBufferSize < MAX_HEADER_SIZE)
 630 mike     1.1         {
 631 krisbash 1.3             LOGD2((ZT("_ReadHeader - Reallocating buffer...")));
 632                          buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
 633 mike     1.1 
 634                          if (!buf)
 635 krisbash 1.3             {
 636                              LOGE2((ZT("_ReadHeader - Cannot allocate memory for larger header")));
 637 mike     1.1                 return PRT_RETURN_FALSE;
 638 krisbash 1.3             }
 639 mike     1.1 
 640                          handler->recvBufferSize *= 2;
 641                          handler->recvBuffer = buf;
 642 krisbash 1.3             LOGD2((ZT("_ReadHeader - Going recursive...")));
 643 mike     1.1             return _ReadHeader(handler);
 644                      }
 645                      else
 646                      {
 647 krisbash 1.3             /* Http header is too big - drop connection */
 648                          trace_HttpHeaderIsTooBig();
 649                          LOGE2((ZT("_ReadHeader - HTTP header is too big. Dropping connection")));
 650 mike     1.1             return PRT_RETURN_FALSE;
 651                      }
 652                  }
 653              
 654                  /* consume data */
 655                  currentLine = buf;
 656                  data = buf + index + 1; /* pointer to data in case we got some */
 657              
 658                  if (!_getRequestLine(handler, &currentLine))
 659 krisbash 1.3     {
 660                      LOGE2((ZT("_ReadHeader - Cannot find request line in HTTP header")));
 661 mike     1.1         return PRT_RETURN_FALSE;
 662 krisbash 1.3     }
 663 mike     1.1 
 664 krisbash 1.3     while ((data - currentLine) > 3)
 665 mike     1.1     {
 666                      if (!_getHeaderField(handler, &currentLine))
 667 krisbash 1.3         {
 668                          LOGE2((ZT("_ReadHeader - Cannot find HTTP header field")));
 669 mike     1.1             return PRT_RETURN_FALSE;
 670 krisbash 1.3         }
 671 mike     1.1     }
 672              
 673                  /* Check if we have to deal with chunked-encoded data */
 674                  if (handler->contentLength < 0)
 675                  {
 676 krisbash 1.3         handler->receivedSize -= index + 1;
 677 mike     1.1 
 678                      /* Invoke user's callback with header information */
 679                      {
 680                          HttpClient* self = (HttpClient*)handler->base.data;
 681              
 682 krisbash 1.4             if (!(*self->callbackOnResponse)(self, self->callbackData, &handler->recvHeaders,
 683 mike     1.1                 handler->contentLength, handler->contentLength == 0, 0))
 684 krisbash 1.3             {
 685                              LOGD2((ZT("_ReadHeader - On response callback for chunked data header failed")));
 686 mike     1.1                 return PRT_RETURN_FALSE;
 687 krisbash 1.3             }
 688 mike     1.1         }
 689              
 690                      /* remove consumed header part */
 691 krisbash 1.3         memmove(handler->recvBuffer, data, handler->receivedSize);
 692 mike     1.1 
 693                      handler->recvingState = RECV_STATE_CHUNKHEADER;
 694                      return PRT_CONTINUE;
 695                  }
 696              
 697 krisbash 1.3     contentSize = (size_t)handler->contentLength;
 698                  if (handler->headVerb)
 699                  {
 700                      LOGD2((ZT("_ReadHeader - HEAD response received. Download will contain %u bytes"), (unsigned int)contentSize));
 701                      contentSize = 0;
 702                  }
 703              
 704 krisbash 1.4     size_t allocSize = 0;
 705                  if (SizeTAdd(sizeof(Page), contentSize, &allocSize) == S_OK &&
 706                      SizeTAdd(allocSize, 1, &allocSize) == S_OK)
 707                  {
 708                      /* Allocate zero-terminated buffer */
 709                      handler->recvPage = (Page*)PAL_Malloc(allocSize);
 710                  }
 711                  else
 712                  {
 713                      // Overflow
 714                      return PRT_RETURN_FALSE;
 715                  }
 716 mike     1.1 
 717 krisbash 1.3     if (handler->recvPage == NULL)
 718                  {
 719                      LOGD2((ZT("_ReadHeader - Cannot allocate memory for received page")));
 720 mike     1.1         return PRT_RETURN_FALSE;
 721 krisbash 1.3     }
 722                  ((char*)(handler->recvPage + 1))[contentSize] = '\0';
 723 mike     1.1 
 724 krisbash 1.3     handler->recvPage->u.s.size = (unsigned int)contentSize;
 725 mike     1.1     handler->recvPage->u.s.next = 0;
 726 krisbash 1.3     handler->receivedSize -= index + 1;
 727 mike     1.1 
 728 krisbash 1.4     /* Verify that we have not more than 'content-length' bytes in buffer left
 729 mike     1.1         If we have more, assuming http client is invalid and drop connection */
 730 krisbash 1.3     if (handler->receivedSize > contentSize)
 731 mike     1.1     {
 732 krisbash 1.3         trace_HttpPayloadIsBiggerThanContentLength();
 733                      LOGE2((ZT("_ReadHeader - HTTP payload is bigger than content-length (%u > %u bytes)"), (unsigned int)handler->receivedSize, (unsigned int)contentSize));
 734 mike     1.1         return PRT_RETURN_FALSE;
 735                  }
 736              
 737 krisbash 1.3     if (handler->receivedSize != 0)
 738                      memcpy(handler->recvPage + 1, data, handler->receivedSize);
 739 mike     1.1     handler->recvingState = RECV_STATE_CONTENT;
 740              
 741                  /* Invoke user's callback with header information */
 742                  {
 743                      HttpClient* self = (HttpClient*)handler->base.data;
 744              
 745 krisbash 1.4         if (!(*self->callbackOnResponse)(self, self->callbackData, &handler->recvHeaders,
 746 mike     1.1             handler->contentLength, handler->contentLength == 0, 0))
 747 krisbash 1.3         {
 748                          LOGE2((ZT("_ReadHeader - On response callback for header failed")));
 749 mike     1.1             return PRT_RETURN_FALSE;
 750 krisbash 1.3         }
 751 mike     1.1     }
 752              
 753 krisbash 1.3     LOGD2((ZT("_ReadHeader - OK exit")));
 754 mike     1.1     return PRT_CONTINUE;
 755              }
 756              
 757              static Http_CallbackResult _ReadData(
 758 krisbash 1.3     HttpClient_SR_SocketData* handler)
 759 mike     1.1 {
 760 krisbash 1.3     /* HttpClient* self = (HttpClient*)handler->base.data; */
 761 mike     1.1     char* buf;
 762                  size_t buf_size, received;
 763                  MI_Result r;
 764              
 765                  /* are we in the right state? */
 766                  if (handler->recvingState != RECV_STATE_CONTENT)
 767                      return PRT_RETURN_FALSE;
 768              
 769 krisbash 1.3     LOGD2((ZT("_ReadData - Begin. Head? %d"), handler->headVerb));
 770                  if (!handler->headVerb)
 771                  {
 772                      buf = (char*)(handler->recvPage + 1) + handler->receivedSize;
 773                      buf_size = (size_t)(handler->contentLength - handler->receivedSize);
 774                      received = 0;
 775              
 776                      if (buf_size != 0)
 777                      {
 778                          r = _Sock_Read(handler, buf, buf_size, &received);
 779                          LOGD2((ZT("_ReadData - _Sock_Read result: %d (%s), socket: %d, recv: %u"), (int)r, mistrerror(r), (int)handler->base.sock, (unsigned int)received));
 780 mike     1.1 
 781 krisbash 1.3             if (r == MI_RESULT_OK && 0 == received)
 782                              return PRT_RETURN_FALSE; /* connection closed */
 783 mike     1.1 
 784 krisbash 1.3             if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
 785                              return PRT_RETURN_FALSE;
 786 mike     1.1 
 787 krisbash 1.3             handler->receivedSize += received;
 788 mike     1.1 
 789 krisbash 1.3             LOGD2((ZT("_RequestCallback - Called _ReadData. %d / %d bytes read"), (int)handler->receivedSize, (int)handler->contentLength));
 790 mike     1.1 
 791 krisbash 1.3             if (handler->contentLength > 0 && handler->receivedSize < (size_t)handler->contentLength)
 792                          {                           /* assume 500 bytes per millisecond transmission */
 793                                                      /* wait to avoid spinning on _Sock_Read */
 794                              unsigned int bytesLeft = (unsigned int)handler->contentLength - (unsigned int)handler->receivedSize;
 795                              unsigned long msec = (unsigned long)(bytesLeft / 500 + 1);
 796 mike     1.1 
 797 krisbash 1.3                 Sleep_Milliseconds(msec);
 798                          }
 799                      }
 800 mike     1.1 
 801 krisbash 1.3         /* did we get all data? */
 802                      LOGD2((ZT("_ReadData - Received size: %d / %d"), (int)handler->receivedSize, (int)handler->contentLength));
 803                      if (handler->receivedSize != (size_t)handler->contentLength)
 804                          return PRT_RETURN_TRUE;
 805                  }
 806 krisbash 1.4 
 807 mike     1.1     /* Invoke user's callback with header information */
 808                  {
 809                      HttpClient* self = (HttpClient*)handler->base.data;
 810 krisbash 1.3         MI_Boolean lastChunk = MI_TRUE;
 811 mike     1.1 
 812 krisbash 1.3         if (handler->contentEnd >= 0 &&
 813                          handler->contentEnd + 1 < handler->contentTotalLength)
 814                      {
 815                          lastChunk = MI_FALSE;
 816                      }
 817              
 818 krisbash 1.4         if (!(*self->callbackOnResponse)(self, self->callbackData, 0,
 819 krisbash 1.3             handler->contentLength, lastChunk, &handler->recvPage))
 820 mike     1.1             return PRT_RETURN_FALSE;
 821              
 822                      /* status callback */
 823                      handler->status = MI_RESULT_OK;
 824                      (*self->callbackOnStatus)(
 825 krisbash 1.4             self,
 826                          self->callbackData,
 827 krisbash 1.3             MI_RESULT_OK);
 828 mike     1.1     }
 829              
 830 krisbash 1.3     if (handler->recvPage != NULL)
 831                  {
 832                      LOGD2((ZT("_ReadData - Freeing recvPage. socket: %d"), (int)handler->base.sock));
 833                      PAL_Free(handler->recvPage);
 834                  }
 835 mike     1.1 
 836 krisbash 1.3     handler->recvPage = NULL;
 837                  handler->receivedSize = 0;
 838 mike     1.1     memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 839                  handler->recvingState = RECV_STATE_HEADER;
 840 krisbash 1.3     LOGD2((ZT("_ReadData - OK exit")));
 841 mike     1.1     return PRT_CONTINUE;
 842              }
 843              
 844              static Http_CallbackResult _ReadChunkHeader(
 845 krisbash 1.3     HttpClient_SR_SocketData* handler)
 846 mike     1.1 {
 847                  char* buf;
 848                  char* currentLine;
 849                  char* data;
 850                  size_t buf_size, received, index;
 851                  MI_Result r;
 852                  MI_Boolean fullHeaderReceived = MI_FALSE;
 853                  MI_Uint32   chunkSize = 0;
 854                  MI_Boolean connectionClosed = MI_FALSE;
 855              
 856                  /* are we done with header? */
 857                  if (handler->recvingState != RECV_STATE_CHUNKHEADER)
 858                      return PRT_CONTINUE;
 859              
 860 krisbash 1.3     buf = handler->recvBuffer + handler->receivedSize;
 861                  buf_size = handler->recvBufferSize - handler->receivedSize;
 862 mike     1.1     received = 0;
 863              
 864                  r = _Sock_Read(handler, buf, buf_size, &received);
 865              
 866 krisbash 1.3     if (r == MI_RESULT_OK && 0 == received)
 867 mike     1.1     {
 868                      if (!handler->recvBufferSize)
 869 krisbash 1.3             return PRT_RETURN_FALSE; /* connection closed */
 870 mike     1.1 
 871                      connectionClosed = MI_TRUE;
 872                  }
 873              
 874 krisbash 1.3     if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
 875 mike     1.1         return PRT_RETURN_FALSE;
 876              
 877                  if (!received && !handler->recvBufferSize)
 878                      return PRT_RETURN_TRUE;
 879              
 880 krisbash 1.3     handler->receivedSize += received;
 881 mike     1.1 
 882                  /* did we get full header? */
 883                  buf = handler->recvBuffer;
 884 krisbash 1.3 
 885                  _Analysis_assume_(handler->recvBufferSize > 2);
 886                  for (index = 1; index < handler->receivedSize && buf[index]; index++)
 887 mike     1.1     {
 888                      if (buf[index-1] == '\r' && buf[index] == '\n' )
 889                      {
 890                          fullHeaderReceived = MI_TRUE;
 891                          break;
 892                      }
 893                  }
 894              
 895 krisbash 1.3     if (!fullHeaderReceived)
 896 mike     1.1     {
 897                      if (connectionClosed)
 898 krisbash 1.3             return PRT_RETURN_FALSE; /* connection closed */
 899 mike     1.1 
 900 krisbash 1.3         if (handler->receivedSize <  handler->recvBufferSize)
 901 mike     1.1             return PRT_RETURN_TRUE; /* continue reading */
 902              
 903 krisbash 1.3         if (handler->recvBufferSize < MAX_HEADER_SIZE)
 904 mike     1.1         {
 905 krisbash 1.3             buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
 906 mike     1.1 
 907                          if (!buf)
 908                              return PRT_RETURN_FALSE;
 909              
 910                          handler->recvBufferSize *= 2;
 911                          handler->recvBuffer = buf;
 912                          return _ReadChunkHeader(handler);
 913                      }
 914                      else
 915                      {
 916                          /* http chunk header is too big - drop connection */
 917 krisbash 1.3             trace_HttpChunkHeaderIsTooBig();
 918 mike     1.1             return PRT_RETURN_FALSE;
 919                      }
 920                  }
 921              
 922                  /* consume data */
 923                  currentLine = buf;
 924                  data = buf + index + 1; /* pointer to data in case we got some */
 925              
 926                  if (!_getChunkSize(currentLine, &chunkSize))
 927                      return PRT_RETURN_FALSE;
 928              
 929                  if (0 == chunkSize)
 930                  {
 931                      /* last chunk received */
 932              
 933                      /* Invoke user's callback with header information */
 934                      {
 935                          HttpClient* self = (HttpClient*)handler->base.data;
 936              
 937 krisbash 1.3             if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
 938 mike     1.1                 handler->contentLength, MI_TRUE, 0))
 939                              return PRT_RETURN_FALSE;
 940              
 941                          /* status callback */
 942                          handler->status = MI_RESULT_OK;
 943                          (*self->callbackOnStatus)(
 944 krisbash 1.3                 self,
 945                              self->callbackData,
 946                              MI_RESULT_OK);
 947 mike     1.1         }
 948              
 949                      /* clean up state */
 950                      handler->recvPage = 0;
 951 krisbash 1.3         handler->receivedSize = 0;
 952 mike     1.1         memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 953                      handler->recvingState = RECV_STATE_HEADER;
 954              
 955                      if (connectionClosed)
 956 krisbash 1.3             return PRT_RETURN_FALSE; /* connection closed */
 957 mike     1.1 
 958                      return PRT_CONTINUE;
 959                  }
 960              
 961 krisbash 1.4     size_t allocSize = 0;
 962                  if (SizeTAdd(sizeof(Page), (size_t)chunkSize, &allocSize) == S_OK &&
 963                      SizeTAdd(allocSize, 2 /*CR-LF*/ + 1 /* \0 */, &allocSize) == S_OK)
 964                  {
 965                      /* Allocate zero-terminated buffer */
 966                      handler->recvPage = (Page*)PAL_Malloc(allocSize);
 967                  }
 968                  else
 969                  {
 970                      // Overflow
 971                      return PRT_RETURN_FALSE;
 972                  }
 973 mike     1.1 
 974                  if (!handler->recvPage)
 975                      return PRT_RETURN_FALSE;
 976              
 977                  ((char*)(handler->recvPage + 1))[chunkSize+2] = 0;
 978              
 979                  handler->recvPage->u.s.size = (unsigned int)chunkSize;
 980                  handler->recvPage->u.s.next = 0;
 981              
 982                  /* subtract header size */
 983 krisbash 1.3     handler->receivedSize -= index + 1;
 984 mike     1.1 
 985                  /* in case of small chunks we may receive more than one chunk already */
 986 krisbash 1.3     if (handler->receivedSize > (size_t)(chunkSize+2))
 987 mike     1.1     {
 988                      /* copy page size to page */
 989 krisbash 1.3         memcpy(handler->recvPage + 1, data, chunkSize+2);
 990 mike     1.1 
 991                      /* notify user */
 992                      {
 993                          HttpClient* self = (HttpClient*)handler->base.data;
 994              
 995 krisbash 1.3             if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
 996 mike     1.1                 handler->contentLength, MI_FALSE, &handler->recvPage))
 997                              return PRT_RETURN_FALSE;
 998              
 999                          if (handler->recvPage)
1000 krisbash 1.3                 PAL_Free(handler->recvPage);
1001 mike     1.1 
1002                          handler->recvPage = 0;
1003                      }
1004              
1005                      /* remove consumed part */
1006 krisbash 1.3         memmove(handler->recvBuffer, data + chunkSize+2, handler->receivedSize - (chunkSize+2));
1007                      handler->receivedSize -= (chunkSize+2);
1008 mike     1.1 
1009                      /* consume next chunk */
1010                      return _ReadChunkHeader(handler);
1011                  }
1012              
1013 krisbash 1.3     memcpy(handler->recvPage + 1, data, handler->receivedSize);
1014 mike     1.1     handler->recvingState = RECV_STATE_CHUNKDATA;
1015              
1016                  if (connectionClosed)
1017 krisbash 1.3         return PRT_RETURN_FALSE; /* connection closed */
1018 mike     1.1 
1019                  return PRT_CONTINUE;
1020              }
1021              static Http_CallbackResult _ReadChunkData(
1022 krisbash 1.3     HttpClient_SR_SocketData* handler)
1023 mike     1.1 {
1024                  //HttpClient* self = (HttpClient*)handler->base.data;
1025                  char* buf;
1026                  size_t buf_size, received;
1027                  MI_Result r;
1028              
1029                  /* are we in the right state? */
1030                  if (handler->recvingState != RECV_STATE_CHUNKDATA)
1031                      return PRT_RETURN_FALSE;
1032              
1033 krisbash 1.3     buf = ((char*)(handler->recvPage + 1)) + handler->receivedSize;
1034                  buf_size = (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */ - handler->receivedSize);
1035 mike     1.1     received = 0;
1036              
1037                  if (buf_size)
1038                  {
1039                      r = _Sock_Read(handler, buf, buf_size, &received);
1040              
1041 krisbash 1.3         if (r == MI_RESULT_OK && 0 == received)
1042                          return PRT_RETURN_FALSE; /* connection closed */
1043 mike     1.1 
1044 krisbash 1.3         if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1045 mike     1.1             return PRT_RETURN_FALSE;
1046              
1047 krisbash 1.3         handler->receivedSize += received;
1048 mike     1.1     }
1049              
1050 krisbash 1.3     if (handler->receivedSize != (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */))
1051                      return PRT_RETURN_TRUE;
1052 mike     1.1 
1053                  /* Invoke user's callback with header information */
1054                  {
1055                      HttpClient* self = (HttpClient*)handler->base.data;
1056              
1057 krisbash 1.3         if (!(*self->callbackOnResponse)( self, self->callbackData, 0,
1058 mike     1.1             handler->contentLength, MI_FALSE, &handler->recvPage))
1059                          return PRT_RETURN_FALSE;
1060              
1061                  }
1062              
1063                  if (handler->recvPage)
1064 krisbash 1.3         PAL_Free(handler->recvPage);
1065 mike     1.1 
1066                  handler->recvPage = 0;
1067 krisbash 1.3     handler->receivedSize = 0;
1068 mike     1.1     memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
1069                  handler->recvingState = RECV_STATE_CHUNKHEADER;
1070                  return PRT_CONTINUE;
1071              }
1072              
1073              static Http_CallbackResult _WriteHeader(
1074 krisbash 1.3     HttpClient_SR_SocketData* handler)
1075 mike     1.1 {
1076                  char* buf;
1077                  size_t buf_size, sent;
1078                  MI_Result r;
1079              
1080                  /* Do we have any data to send? */
1081                  if (!handler->sendHeader)
1082                      return PRT_RETURN_TRUE;
1083              
1084                  /* are we done with header? */
1085                  if (handler->sendingState == RECV_STATE_CONTENT)
1086                      return PRT_CONTINUE;
1087              
1088 krisbash 1.3     LOGD2((ZT("_WriteHeader - Begin")));
1089              
1090 mike     1.1     buf = ((char*)(handler->sendHeader + 1)) + handler->sentSize;
1091                  buf_size = handler->sendHeader->u.s.size - handler->sentSize;
1092                  sent = 0;
1093              
1094                  r = _Sock_Write(handler, buf, buf_size, &sent);
1095 krisbash 1.3     LOGD2((ZT("_WriteHeader - _Sock_Write result: %d (%s), socket: %d, sent: %d"), (int)r, mistrerror(r), (int)handler->base.sock, (int)sent));
1096 mike     1.1 
1097 krisbash 1.3     if (r == MI_RESULT_OK && 0 == sent)
1098                  {
1099                      LOGE2((ZT("_WriteHeader - Connection closed")));
1100                      return PRT_RETURN_FALSE; /* connection closed */
1101                  }
1102 mike     1.1 
1103 krisbash 1.3     if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1104                  {
1105                      LOGE2((ZT("_WriteHeader - _Sock_Write returned error: %d (%s)"), (int)r, mistrerror(r)));
1106 mike     1.1         return PRT_RETURN_FALSE;
1107 krisbash 1.3     }
1108 mike     1.1 
1109                  handler->sentSize += sent;
1110 krisbash 1.3     handler->headVerb = buf_size > 4 && Strncasecmp(buf, "HEAD", 4) == 0;
1111 mike     1.1 
1112 krisbash 1.3     /* did we send all data? */
1113                  if (handler->sentSize != handler->sendHeader->u.s.size)
1114                  {
1115                      LOGD2((ZT("_WriteHeader - Partial write. %u sent this time, %u / %d written, result: %d (%s)"), (unsigned int)sent, (unsigned int)handler->sentSize, (unsigned int)handler->sendHeader->u.s.size, r, mistrerror(r)));
1116                      return PRT_RETURN_TRUE;
1117                  }
1118 mike     1.1 
1119 krisbash 1.3     PAL_Free(handler->sendHeader);
1120 mike     1.1     handler->sendHeader = 0;
1121                  handler->sentSize = 0;
1122                  handler->sendingState = RECV_STATE_CONTENT;
1123              
1124 krisbash 1.3     LOGD2((ZT("_WriteHeader - OK exit")));
1125 mike     1.1     return PRT_CONTINUE;
1126              }
1127              
1128              static Http_CallbackResult _WriteData(
1129 krisbash 1.3     HttpClient_SR_SocketData* handler)
1130 mike     1.1 {
1131                  char* buf;
1132                  size_t buf_size, sent;
1133                  MI_Result r;
1134              
1135 krisbash 1.3     LOGD2((ZT("_WriteData - Begin")));
1136 mike     1.1     /* are we in the right state? */
1137                  if (handler->sendingState != RECV_STATE_CONTENT)
1138 krisbash 1.3     {
1139                      LOGE2((ZT("_WriteData - Wrong state. state: %d"), handler->sendingState));
1140 mike     1.1         return PRT_RETURN_FALSE;
1141 krisbash 1.3     }
1142 mike     1.1 
1143                  if (!handler->sendPage)
1144                  {   /* no content*/
1145                      handler->sentSize = 0;
1146                      handler->sendingState = RECV_STATE_HEADER;
1147                      handler->base.mask &= ~SELECTOR_WRITE;
1148                      handler->base.mask |= SELECTOR_READ;
1149              
1150 krisbash 1.3         LOGW2((ZT("_WriteData - Content is empty. Continuing")));
1151 mike     1.1         return PRT_CONTINUE;
1152                  }
1153              
1154                  buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
1155                  buf_size = handler->sendPage->u.s.size - handler->sentSize;
1156                  sent = 0;
1157              
1158                  r = _Sock_Write(handler, buf, buf_size, &sent);
1159 krisbash 1.3     LOGD2((ZT("_WriteData - HTTPClient sent %u / %u bytes with result %d (%s)"), (unsigned int)sent, (unsigned int)buf_size, (int)r, mistrerror(r)));
1160 mike     1.1 
1161 krisbash 1.3     if (r == MI_RESULT_OK && 0 == sent)
1162                  {
1163                      LOGE2((ZT("_WriteData exit. Connection closed")));
1164                      return PRT_RETURN_FALSE; /* connection closed */
1165                  }
1166 mike     1.1 
1167 krisbash 1.3     if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1168                  {
1169                      LOGE2((ZT("_WriteData exit - Error: %d (%s)"), r, mistrerror(r)));
1170 mike     1.1         return PRT_RETURN_FALSE;
1171 krisbash 1.3     }
1172 mike     1.1 
1173                  handler->sentSize += sent;
1174              
1175 krisbash 1.3     /* did we send all data? */
1176 mike     1.1 
1177 krisbash 1.3     if (handler->sentSize != handler->sendPage->u.s.size)
1178                  {
1179                      LOGD2((ZT("_WriteData - Exit. Partial write. %u / %u bytes written"), (unsigned int)handler->sentSize, (unsigned int)handler->sendPage->u.s.size));
1180 mike     1.1         return PRT_RETURN_TRUE;
1181 krisbash 1.3     }
1182              
1183                  LOGD2((ZT("_WriteData - %u / %u bytes sent"), (unsigned int)handler->sentSize, (unsigned int)handler->sendPage->u.s.size));
1184                  PAL_Free(handler->sendPage);
1185                  handler->sendPage = NULL;
1186 mike     1.1     handler->sentSize = 0;
1187                  handler->sendingState = RECV_STATE_HEADER;
1188                  handler->base.mask &= ~SELECTOR_WRITE;
1189                  handler->base.mask |= SELECTOR_READ;
1190              
1191 krisbash 1.3     LOGD2((ZT("_WriteData - OK exit. returning: %d"), PRT_CONTINUE));
1192              
1193 mike     1.1     return PRT_CONTINUE;
1194              }
1195              
1196              static MI_Boolean _RequestCallbackRead(
1197 krisbash 1.3     HttpClient_SR_SocketData* handler)
1198 mike     1.1 {
1199                  switch (_ReadHeader(handler))
1200                  {
1201                  case PRT_CONTINUE: break;
1202                  case PRT_RETURN_TRUE: return MI_TRUE;
1203                  case PRT_RETURN_FALSE: return MI_FALSE;
1204                  }
1205              
1206                  if (handler->recvingState == RECV_STATE_CONTENT)
1207                  {
1208                      switch (_ReadData(handler))
1209                      {
1210                      case PRT_CONTINUE: break;
1211                      case PRT_RETURN_TRUE: return MI_TRUE;
1212                      case PRT_RETURN_FALSE: return MI_FALSE;
1213                      }
1214                  }
1215              
1216                  if (handler->recvingState == RECV_STATE_CHUNKHEADER)
1217                  {
1218                      switch (_ReadChunkHeader(handler))
1219 mike     1.1         {
1220                      case PRT_CONTINUE: break;
1221                      case PRT_RETURN_TRUE: return MI_TRUE;
1222                      case PRT_RETURN_FALSE: return MI_FALSE;
1223                      }
1224                  }
1225                  if (handler->recvingState == RECV_STATE_CHUNKDATA)
1226                  {
1227                      switch (_ReadChunkData(handler))
1228                      {
1229                      case PRT_CONTINUE: break;
1230                      case PRT_RETURN_TRUE: return MI_TRUE;
1231                      case PRT_RETURN_FALSE: return MI_FALSE;
1232                      }
1233                  }
1234              
1235                  return MI_TRUE;
1236              }
1237              
1238              static MI_Boolean _RequestCallbackWrite(
1239 krisbash 1.3     HttpClient_SR_SocketData* handler)
1240 mike     1.1 {
1241                  switch (_WriteHeader(handler))
1242                  {
1243                  case PRT_CONTINUE: break;
1244                  case PRT_RETURN_TRUE: return MI_TRUE;
1245                  case PRT_RETURN_FALSE: return MI_FALSE;
1246                  }
1247              
1248                  switch (_WriteData(handler))
1249                  {
1250                  case PRT_CONTINUE: break;
1251                  case PRT_RETURN_TRUE: return MI_TRUE;
1252                  case PRT_RETURN_FALSE: return MI_FALSE;
1253                  }
1254                  return MI_TRUE;
1255              }
1256              
1257              
1258              static MI_Boolean _RequestCallback(
1259                  Selector* sel,
1260                  Handler* handlerIn,
1261 krisbash 1.3     MI_Uint32 mask,
1262 mike     1.1     MI_Uint64 currentTimeUsec)
1263              {
1264 krisbash 1.3     HttpClient_SR_SocketData* handler = (HttpClient_SR_SocketData*)handlerIn;
1265                  MI_UNUSED(sel);
1266 mike     1.1 
1267 krisbash 1.3     if (((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
1268                      ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations))
1269 mike     1.1     {
1270                      if (!_RequestCallbackRead(handler))
1271 krisbash 1.3         {
1272                          LOGE2((ZT("_RequestCallback - RequestCallbackRead failed")));
1273 mike     1.1             return MI_FALSE;
1274 krisbash 1.3         }
1275                      LOGD2((ZT("_RequestCallback - Called _RequestCallbackRead. %u / %u bytes read"), (unsigned int)handler->receivedSize, handler->recvPage == NULL ? 0 : (unsigned int)handler->recvPage->u.s.size));
1276 mike     1.1     }
1277              
1278 krisbash 1.3     if (((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
1279                      ((mask & SELECTOR_READ) != 0 && handler->reverseOperations))
1280 mike     1.1     {
1281                      if (!_RequestCallbackWrite(handler))
1282 krisbash 1.3         {
1283                          LOGE2((ZT("_RequestCallback - _RequestCallbackWrite failed")));
1284 mike     1.1             return MI_FALSE;
1285 krisbash 1.3         }
1286                      LOGD2((ZT("_RequestCallback - Called _RequestCallbackWrite. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1287                      while (handler->sendPage != NULL && handler->sentSize < handler->sendPage->u.s.size)
1288                      {                               /* assume 500 bytes per millisecond transmission */
1289                                                      /* wait after to avoid spinning too much on _WriteData */
1290                          unsigned int bytesLeft = (unsigned int)handler->sendPage->u.s.size - (unsigned int)handler->sentSize;
1291                          unsigned long msec = (unsigned long)(bytesLeft / 500 + 1);
1292              
1293                          LOGD2((ZT("_RequestCallback - Called _WriteData. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1294                          if (_WriteData(handler) == MI_FALSE)
1295                          {
1296                              LOGE2((ZT("_RequestCallback - _WriteData failed")));
1297                              return MI_FALSE;
1298                          }
1299                          LOGD2((ZT("_RequestCallback - Called _WriteData. %u bytes written, %u bytes left"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1300                          Sleep_Milliseconds(msec);
1301                      }
1302                      LOGD2((ZT("_RequestCallback - Called _RequestCallbackWrite. %u / %u bytes sent"), (unsigned int)handler->sentSize, handler->sendPage == NULL ? 0 : (unsigned int)handler->sendPage->u.s.size));
1303 mike     1.1     }
1304 krisbash 1.4 
1305 mike     1.1     /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
1306                  if (mask & (SELECTOR_READ | SELECTOR_WRITE))
1307                  {
1308                      handler->base.fireTimeoutAt = currentTimeUsec + handler->timeoutUsec;
1309                  }
1310              
1311 krisbash 1.3     /* Close connection by timeout */
1312                  if ((mask & SELECTOR_TIMEOUT) != 0)
1313 mike     1.1     {
1314 krisbash 1.3         if (handler->status != MI_RESULT_OK)
1315                      {
1316                          handler->recvHeaders.httpError = 408;
1317 mike     1.1             handler->status = MI_RESULT_TIME_OUT;
1318 krisbash 1.3         }
1319                      LOGE2((ZT("_RequestCallback - Timed out. socket: %d, result: %d (%s)"), handler->base.sock, handler->status, mistrerror(handler->status)));
1320 mike     1.1         return MI_FALSE;
1321                  }
1322              
1323 krisbash 1.3     if ((mask & SELECTOR_REMOVE) != 0 || (mask & SELECTOR_DESTROY) != 0)
1324 mike     1.1     {
1325                      HttpClient* self = (HttpClient*)handler->base.data;
1326              
1327                      /* notify next stack layer */
1328 krisbash 1.3         if (handler->status != MI_RESULT_OK)
1329                          (*self->callbackOnStatus)(self, self->callbackData, handler->status);
1330              
1331                      /* Yeah, this is hokey, but we need to sleep here to let the */
1332              		/* subsystems have the opportunity to send the data before we close */
1333              		/* the socket, or we'll get a broken pipe/connection reset */
1334              #if defined(CONFIG_OS_WINDOWS)
1335                      Sleep_Milliseconds(1);
1336              #else
1337                      usleep(50);
1338              #endif
1339              
1340                      if (handler == NULL)
1341                      {
1342                          LOGE2((ZT("_RequestCallback - The handler object was free'd under us!")));
1343                          return MI_TRUE;
1344                      }
1345 mike     1.1 
1346 krisbash 1.3         self->connector = NULL;
1347 mike     1.1 
1348                      if (handler->ssl)
1349                          SSL_free(handler->ssl);
1350              
1351                      Sock_Close(handler->base.sock);
1352              
1353                      if (handler->recvPage)
1354 krisbash 1.3             PAL_Free(handler->recvPage);
1355 mike     1.1 
1356                      if (handler->sendPage)
1357 krisbash 1.3             PAL_Free(handler->sendPage);
1358 mike     1.1 
1359                      if (handler->sendHeader)
1360 krisbash 1.3             PAL_Free(handler->sendHeader);
1361 mike     1.1 
1362 krisbash 1.3         PAL_Free(handler->recvBuffer);
1363                      PAL_Free(handler);
1364 mike     1.1     }
1365              
1366                  return MI_TRUE;
1367              }
1368              
1369              #ifdef CONFIG_POSIX
1370 krisbash 1.3 
1371              /*
1372               Verify callback when the server authentication certificate's chain of trust is checked. This
1373               is the same as the Open SSL verify callback function (return preverify_ok), except that it
1374               logs a diagnostic message when preverify_ok has a failed status.
1375              */
1376              static int _ctxVerify(
1377                  int preverify_ok,
1378                  X509_STORE_CTX* ctx)
1379 mike     1.1 {
1380 krisbash 1.3     if (preverify_ok <= 0)
1381                  {
1382                      X509* certWithError = X509_STORE_CTX_get_current_cert(ctx);
1383                      int error = X509_STORE_CTX_get_error(ctx);
1384                      char nameBuf[256];
1385 mike     1.1 
1386 krisbash 1.3         X509_NAME_oneline(X509_get_subject_name(certWithError), nameBuf, 256);
1387                      trace_SSL_VerifyFailed(error, nameBuf);
1388                  }
1389                  return preverify_ok;
1390              }
1391 mike     1.1 
1392 krisbash 1.3 /*
1393               Create an Open SSL context that will be used for secure communication. Set up server and client
1394               certificate authentication if specified.
1395              */
1396              static MI_Result _CreateSSLContext(
1397                  HttpClient* self,
1398                  const char* trustedCertsDir,
1399                  const char* certFile,
1400                  const char* privateKeyFile)
1401              {
1402                  SSL_CTX* sslContext = SSL_CTX_new(SSLv23_method());
1403                  if (sslContext == NULL)
1404 mike     1.1     {
1405 krisbash 1.3         LOGE2((ZT("_CreateSSLContext - Cannot create SSL context")));
1406                      trace_SSL_CannotCreateContext();
1407 mike     1.1         return MI_RESULT_FAILED;
1408                  }
1409                  SSL_CTX_set_quiet_shutdown(sslContext, 1);
1410 krisbash 1.3     (void)SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE);
1411 mike     1.1     SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
1412 krisbash 1.3     SSL_CTX_sess_set_remove_cb(sslContext, NULL);
1413              
1414                  if (trustedCertsDir != NULL)
1415 mike     1.1     {
1416 krisbash 1.3         /* Cause Open SSL to check the server certificate Subject against its FQDN and
1417                      ** to check the server certificate chain against the contents of *trustedCertsDir.
1418                      */
1419                      if (SSL_CTX_load_verify_locations(sslContext, NULL, trustedCertsDir) < 0)
1420 mike     1.1         {
1421 krisbash 1.3             LOGE2((ZT("_CreateSSLContext - Cannot set directory containing trusted certificate(s) to %s"), trustedCertsDir));
1422                          trace_SSL_BadTrustDir(trustedCertsDir);
1423 mike     1.1         }
1424 krisbash 1.3         SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER, _ctxVerify);
1425 mike     1.1     }
1426              
1427 krisbash 1.3     /* Check if there is a client certificate file (file containing client authentication
1428                  ** certificate) specified. If specified, validate and load the certificate.
1429 mike     1.1     */
1430 krisbash 1.3     if (certFile != NULL && *certFile != '\0')
1431 mike     1.1     {
1432 krisbash 1.3         int err;
1433              
1434                      /* load the specified client certificates */
1435                      LOGD2((ZT("_CreateSSLContext - Loading server certificate from: %s"), certFile));
1436              
1437                      err = SSL_CTX_use_certificate_file(sslContext,
1438                                                         certFile,
1439                                                         strcmp(certFile + strlen(certFile) - 4, ".pem") == 0 ? SSL_FILETYPE_PEM :  SSL_FILETYPE_ASN1);
1440                      if (err <= 0)
1441                      {
1442              #if defined(ENABLE_TRACING)
1443                          unsigned long error = ERR_peek_last_error();
1444              #endif
1445              
1446                          LOGE2((ZT("_CreateSSLContext - No client certificate found in %s"), certFile));
1447                          LOGE2((ZT("_CreateSSLContext - OpenSSL Error 0x%lX (%s) in SSL_CTX_use_certificate_file"), error, sslstrerror(error)));
1448 mike     1.1             SSL_CTX_free(sslContext);
1449 krisbash 1.3             sslContext = NULL;
1450 mike     1.1             return MI_RESULT_FAILED;
1451                      }
1452 krisbash 1.3 
1453                      if (privateKeyFile != NULL && *privateKeyFile != '\0')
1454                      {
1455                          /* load the specified private key */
1456                          LOGD2((ZT("_CreateSSLContext - SSL Loading client private key from: %s"), privateKeyFile));
1457              
1458                          err = SSL_CTX_use_RSAPrivateKey_file(sslContext,
1459                                                               privateKeyFile,
1460                                                               strcmp(privateKeyFile + strlen(privateKeyFile) - 4, ".pem") == 0 ? SSL_FILETYPE_PEM :  SSL_FILETYPE_ASN1);
1461                          if (err <= 0)
1462                          {
1463              #if defined(ENABLE_TRACING)
1464                              unsigned long error = ERR_peek_last_error();
1465              #endif
1466                              LOGE2((ZT("_CreateSSLContext - Invalid private key found in %s"), privateKeyFile));
1467                              LOGE2((ZT("_CreateSSLContext - OpenSSL error 0x%lX (%s) in SSL_CTX_use_PrivateKey_file"), error, sslstrerror(error)));
1468                              SSL_CTX_free(sslContext);
1469                              sslContext = NULL;
1470                              return MI_RESULT_FAILED;
1471                          }
1472                      }
1473 mike     1.1     }
1474 krisbash 1.3 
1475 mike     1.1     self->sslContext = sslContext;
1476                  return MI_RESULT_OK;
1477              }
1478 krisbash 1.3 
1479 mike     1.1 #endif
1480              
1481 krisbash 1.3 static MI_Result _CreateSocketAndConnect(
1482                  Sock* s,
1483                  Addr* addr)
1484              {
1485                  MI_Result r;
1486              
1487                  LOGD2((ZT("_CreateSocketAndConnect - Begin")));
1488              
1489                  /* Create client socket. */
1490                  r = Sock_Create(s, addr->is_ipv6);
1491                  if (r != MI_RESULT_OK)
1492                  {
1493                      LOGE2((ZT("_CreateSocketAndConnect - Sock_Create failed. result: %d (%s)"), r, mistrerror(r)));
1494                      return r;
1495                  }
1496              
1497                  /* set the socket to be non-blocking */
1498                  r = Sock_SetBlocking(*s, MI_FALSE);
1499                  if (r != MI_RESULT_OK)
1500                  {
1501                      LOGE2((ZT("_CreateSocketAndConnect - Sock_SetBlocking failed. result: %d (%s)"), r, mistrerror(r)));
1502 krisbash 1.3         return r;
1503                  }
1504              
1505                  /* connect the socket to the IP address */
1506                  r = Sock_Connect(*s, addr);
1507                  if (r != MI_RESULT_OK)
1508                  {
1509                      LOGE2((ZT("_CreateSocketAndConnect - Sock_Connect failed. result: %d (%s)"), r, mistrerror(r)));
1510                      return r;
1511                  }
1512              
1513                  LOGD2((ZT("_CreateSocketAndConnect - OK exit")));
1514              
1515                  return MI_RESULT_WOULD_BLOCK;
1516              }
1517              
1518 mike     1.1 static MI_Result _CreateConnectorSocket(
1519                  HttpClient* self,
1520                  const char* host,
1521                  unsigned short port,
1522                  MI_Boolean secure)
1523              {
1524                  Addr addr;
1525                  MI_Result r;
1526                  Sock s;
1527 krisbash 1.3     HttpClient_SR_SocketData* h;
1528 mike     1.1     MI_Uint64 currentTimeUsec;
1529              
1530 krisbash 1.3     LOGD2((ZT("_CreateConnectorSocket - Begin. host: %s, port: %d, secure? %d"), host, port, secure));
1531              
1532 mike     1.1     /* timeout calculation */
1533 krisbash 1.3     if (PAL_Time(&currentTimeUsec) != PAL_TRUE)
1534 mike     1.1     {
1535 krisbash 1.3         LOGE2((ZT("_CreateConnectorSocket - PAL_Time failed")));
1536 mike     1.1         return MI_RESULT_FAILED;
1537                  }
1538              
1539 krisbash 1.3     /* This code tries to connect using the preferred addressing family (IPv4 */
1540              	/* or IPv6). If that fails and Addr_Init has a secondary addressing */
1541              	/* family, a connection with the secondary family, it tries using the */
1542              	/* secondary family next. */
1543              
1544                  /* Initialize preferred address */
1545                  r = Addr_Init(&addr, host, port, MI_FALSE);
1546 mike     1.1     if (r != MI_RESULT_OK)
1547                  {
1548 krisbash 1.3         LOGE2((ZT("_CreateConnectorSocket - Addr_Init failed. result: %d (%s)"), r, mistrerror(r)));
1549                      return r;
1550 mike     1.1     }
1551              
1552 krisbash 1.3     /* Connect to the server */
1553                  r = _CreateSocketAndConnect(&s, &addr);
1554 mike     1.1     if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1555                  {
1556 krisbash 1.3         MI_Result r2;
1557              
1558 mike     1.1         Sock_Close(s);
1559 krisbash 1.3 
1560                      LOGW2((ZT("_CreateConnectorSocket - _CreateSocketAndConnect of primary address failed. result: %d (%s)"), r, mistrerror(r)));
1561              
1562                      /* Initialize secondary address */
1563                      r2 = Addr_Init(&addr, host, port, MI_TRUE);
1564                      if (r2 != MI_RESULT_OK)
1565                          return r;                   /* on error, return original failure */
1566                      r2 = _CreateSocketAndConnect(&s, &addr);
1567                      if (r2 != MI_RESULT_OK && r2 != MI_RESULT_WOULD_BLOCK)
1568                      {
1569                          Sock_Close(s);
1570              
1571                          LOGE2((ZT("_CreateConnectorSocket - Addr_Init failed. result: %d (%s)"), r, mistrerror(r)));
1572 krisbash 1.4 
1573 krisbash 1.3             return r;                   /* on error, return original failure */
1574                      }
1575                      r = r2;
1576 mike     1.1     }
1577              
1578                  /* Create handler */
1579 krisbash 1.3     h = (HttpClient_SR_SocketData*)PAL_Calloc(1, sizeof(HttpClient_SR_SocketData));
1580 mike     1.1 
1581 krisbash 1.3     if (h == NULL)
1582 mike     1.1     {
1583                      Sock_Close(s);
1584 krisbash 1.3         LOGE2((ZT("_CreateConnectorSocket - calloc failed")));
1585 mike     1.1         return MI_RESULT_FAILED;
1586                  }
1587              
1588                  h->recvBufferSize = INITIAL_BUFFER_SIZE;
1589 krisbash 1.3     h->recvBuffer = (char*)PAL_Calloc(1, h->recvBufferSize);
1590 mike     1.1     if (!h->recvBuffer)
1591                  {
1592 krisbash 1.3         PAL_Free(h);
1593 mike     1.1         Sock_Close(s);
1594 krisbash 1.3         LOGE2((ZT("_CreateConnectorSocket - calloc failed")));
1595 mike     1.1         return MI_RESULT_FAILED;
1596                  }
1597              
1598                  h->base.sock = s;
1599                  h->base.mask = SELECTOR_EXCEPTION;
1600                  h->base.callback = _RequestCallback;
1601                  h->base.data = self;
1602                  h->timeoutUsec = DEFAULT_HTTP_TIMEOUT_USEC;
1603                  h->base.fireTimeoutAt = currentTimeUsec + h->timeoutUsec;
1604              
1605 krisbash 1.3     /* SSL support */
1606 mike     1.1     if (secure)
1607                  {
1608                      h->ssl = SSL_new(self->sslContext);
1609              
1610                      if (!h->ssl)
1611                      {
1612 krisbash 1.3             LOGW2((ZT("_CreateConnectorSocket - SSL_new failed")));
1613                          trace_SSLNew_Failed();
1614                          PAL_Free(h);
1615 mike     1.1             Sock_Close(s);
1616                          return MI_RESULT_FAILED;
1617                      }
1618              
1619 krisbash 1.3         Sock_SetBlocking(s, MI_TRUE);
1620 mike     1.1         if (!(SSL_set_fd(h->ssl, s) ))
1621                      {
1622 krisbash 1.3             LOGW2((ZT("_CreateConnectorSocket - SSL_set_fd failed")));
1623                          trace_SSL_setfd_Failed();
1624 mike     1.1             SSL_free(h->ssl);
1625 krisbash 1.3             PAL_Free(h);
1626 mike     1.1             Sock_Close(s);
1627                          return MI_RESULT_FAILED;
1628                      }
1629              
1630                      SSL_set_connect_state(h->ssl);
1631                  }
1632              
1633                  /* Watch for read events on the incoming connection */
1634                  r = Selector_AddHandler(self->selector, &h->base);
1635              
1636                  if (r != MI_RESULT_OK)
1637                  {
1638 krisbash 1.3         LOGE2((ZT("_CreateConnectorSocket - Selector_AddHandler failed with error: %d (%s)"), (int)r, mistrerror(r)));
1639                      trace_SelectorAddHandler_Failed();
1640 mike     1.1         if (secure)
1641                          SSL_free(h->ssl);
1642 krisbash 1.3         PAL_Free(h);
1643 mike     1.1         Sock_Close(s);
1644                      return MI_RESULT_FAILED;
1645                  }
1646              
1647                  self->connector = h;
1648              
1649 krisbash 1.3     LOGD2((ZT("_CreateConnectorSocket - OK exit. socket: %d, secure: %d, timeout: %s"), h->base.sock, secure, FmtInterval(h->base.fireTimeoutAt - currentTimeUsec)));
1650              
1651 mike     1.1     return MI_RESULT_OK;
1652              }
1653              
1654              static MI_Result _New_Http(
1655                  HttpClient** selfOut,
1656                  Selector* selector, /*optional, maybe NULL*/
1657                  HttpClientCallbackOnStatus statusCallback,
1658                  HttpClientCallbackOnResponse  responseCallback,
1659                  void* callbackData)
1660              {
1661                  HttpClient* self;
1662              
1663                  /* Check parameters */
1664                  if (!selfOut)
1665                      return MI_RESULT_INVALID_PARAMETER;
1666              
1667                  /* Clear output parameter */
1668                  *selfOut = NULL;
1669              
1670                  /* Allocate structure */
1671                  {
1672 krisbash 1.3         self = (HttpClient*)PAL_Calloc(1, sizeof(HttpClient));
1673 mike     1.1 
1674                      if (!self)
1675                          return MI_RESULT_FAILED;
1676                  }
1677              
1678                  if (selector)
1679                  {   /* attach the exisiting selector */
1680                      self->selector = selector;
1681                      self->internalSelectorUsed = MI_FALSE;
1682                  }
1683                  else
1684                  {   /* creaet a new selector */
1685                      /* Initialize the network */
1686                      Sock_Start();
1687              
1688                      /* Initialize the selector */
1689                      if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1690                      {
1691 krisbash 1.3             PAL_Free(self);
1692                          LOGE2((ZT("_NewHttp - Selector_Init failed")));
1693 mike     1.1             return MI_RESULT_FAILED;
1694                      }
1695                      self->selector = &self->internalSelector;
1696                      self->internalSelectorUsed = MI_TRUE;
1697                  }
1698              
1699                  /* Save the callback and callbackData */
1700                  self->callbackOnResponse = responseCallback;
1701                  self->callbackOnStatus = statusCallback;
1702                  self->callbackData = callbackData;
1703              
1704                  /* Set the magic number */
1705                  self->magic = _MAGIC;
1706              
1707                  /* Set output parameter */
1708                  *selfOut = self;
1709                  return MI_RESULT_OK;
1710              }
1711              
1712              
1713              
1714 mike     1.1 static size_t _GetHeadersSize(
1715                  const HttpClientRequestHeaders* headers)
1716              {
1717                  size_t res = 0;
1718                  size_t index = 0;
1719              
1720                  while (index < headers->size)
1721                  {
1722                      res += Strlen(headers->data[index]);
1723                      res += 2; /* \r \n pair */
1724                      index++;
1725                  }
1726              
1727                  return res;
1728              }
1729              
1730              static Page* _CreateHttpHeader(
1731                  const char* verb,
1732                  const char* uri,
1733                  const HttpClientRequestHeaders* headers,
1734                  size_t size)
1735 mike     1.1 {
1736                  Page* page = 0;
1737                  size_t pageSize = 0;
1738                  int r;
1739                  char* p;
1740              
1741              #define HTTP_HEADER_FORMAT "%s %s HTTP/1.1\r\n" \
1742                  "Content-Length: %d\r\n"\
1743                  "Connection: Keep-Alive\r\n" \
1744                  "Host: host\r\n"
1745              
1746              #define HTTP_HEADER_FORMAT_NOCL "%s %s HTTP/1.1\r\n" \
1747                  "Connection: Keep-Alive\r\n" \
1748                  "Host: host\r\n"
1749              
1750                  /* calculate approximate page size */
1751                  if (!verb)
1752                      verb = "POST";
1753 krisbash 1.4 
1754 mike     1.1     pageSize += sizeof(HTTP_HEADER_FORMAT) + 10; /* format + 10 digits of content length */
1755              
1756 krisbash 1.4     if (SizeTAdd(pageSize, Strlen(verb), &pageSize) != S_OK ||
1757                      SizeTAdd(pageSize, Strlen(uri),  &pageSize) != S_OK ||
1758                      SizeTAdd(pageSize, sizeof(Page), &pageSize) != S_OK ||
1759                      (headers && SizeTAdd(pageSize, _GetHeadersSize(headers), &pageSize)) != S_OK)
1760                  {
1761                      // Overflow
1762                      return 0;
1763                  }
1764 mike     1.1 
1765 krisbash 1.4     page = (Page*)PAL_Malloc(pageSize);
1766 mike     1.1 
1767                  if (!page)
1768                      return 0;
1769              
1770                  /* clear header */
1771                  memset(page, 0, sizeof(Page));
1772              
1773                  p = (char*)(page + 1);
1774              
1775                  if (size)
1776                      r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT, verb, uri, (int)size);
1777                  else
1778                      r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT_NOCL, verb, uri);
1779              
1780                  if (r < 0)
1781                  {
1782 krisbash 1.3         PAL_Free(page);
1783 mike     1.1         return 0;
1784                  }
1785              
1786                  p += r;
1787                  pageSize -= r;
1788              
1789                  if (headers)
1790                  {
1791                      size_t index = 0;
1792              
1793                      while (index < headers->size)
1794                      {
1795                          r = (int)Strlcpy(p,headers->data[index], pageSize);
1796                          p += r;
1797                          pageSize -= r;
1798                          r = (int)Strlcpy(p,"\r\n", pageSize);
1799                          p += r;
1800                          pageSize -= r;
1801              
1802                          index++;
1803                      }
1804 mike     1.1     }
1805              
1806                  /* add trailing \r\n */
1807                  r = (int)Strlcpy(p,"\r\n", pageSize);
1808                  p += r;
1809                  pageSize -= r;
1810              
1811                  page->u.s.size = (unsigned int)(p - (char*)(page+1));
1812              
1813                  return page;
1814              }
1815              
1816              /* ************************************************************************* *\
1817                                              HTTP CLIENT
1818              \* ************************************************************************* */
1819              /*
1820                  Creates new http client.
1821              
1822                  Parameters:
1823                  selfOut - [out] newly created http object (or null if failed).
1824                  selector - [opt] selector to use for socket monitoring. If selector not specified,
1825 mike     1.1             private one is created.
1826                  host - host address
1827                  port - port number
1828                  secure - flag that indicates if http or https conneciton is required
1829              
1830                  Returns:
1831                  'OK' on success or error code otherwise
1832              */
1833              MI_Result HttpClient_New_Connector(
1834                  HttpClient** selfOut,
1835                  Selector* selector, /*optional, maybe NULL*/
1836                  const char* host,
1837                  unsigned short port,
1838                  MI_Boolean secure,
1839                  HttpClientCallbackOnStatus statusCallback,
1840                  HttpClientCallbackOnResponse  responseCallback,
1841 krisbash 1.3     void* callbackData,
1842                  const char* trustedCertsDir,
1843                  const char* certFile,
1844                  const char* privateKeyFile)
1845 mike     1.1 {
1846                  HttpClient* self;
1847                  MI_Result r;
1848              
1849                  /* allocate this, inits selector */
1850 krisbash 1.3     r = _New_Http(selfOut, selector, statusCallback,
1851                                responseCallback, callbackData);
1852 mike     1.1 
1853                  if (MI_RESULT_OK != r)
1854 krisbash 1.3     {
1855                      LOGE2((ZT("HttpClient_New_Connector - _New_Http failed. result: %d (%s)"), r, mistrerror(r)));
1856 mike     1.1         return r;
1857 krisbash 1.3     }
1858 mike     1.1     self = *selfOut;
1859              
1860              #ifdef CONFIG_POSIX
1861 krisbash 1.3     /* Allocate SSL context */
1862 mike     1.1     if (secure)
1863                  {
1864                      /* init ssl */
1865                      SSL_library_init();
1866              
1867                      /* create context */
1868 krisbash 1.3         r = _CreateSSLContext(self, trustedCertsDir, certFile, privateKeyFile);
1869 mike     1.1 
1870                      if (r != MI_RESULT_OK)
1871                      {
1872                          HttpClient_Delete(self);
1873 krisbash 1.3             *selfOut = NULL;
1874                          LOGE2((ZT("HttpClient_New_Connector - _CreateSSLContext failed. result: %d (%s)"), r, mistrerror(r)));
1875 mike     1.1             return r;
1876                      }
1877                  }
1878              #else
1879                  MI_UNUSED(secure);
1880              #endif
1881              
1882                  /* Create http connector socket */
1883                  {
1884                      r = _CreateConnectorSocket(self, host, port, secure);
1885              
1886                      if (r != MI_RESULT_OK)
1887                      {
1888                          HttpClient_Delete(self);
1889 krisbash 1.3             LOGE2((ZT("HttpClient_New_Connector - _CreateConnectorSocket failed failed. result: %d (%s)"), r, mistrerror(r)));
1890 mike     1.1             return r;
1891                      }
1892                  }
1893              
1894                  return MI_RESULT_OK;
1895              }
1896              
1897              /*
1898                  Deletes http object, disconnects form the server
1899                  and frees all related resources.
1900 krisbash 1.3 
1901 mike     1.1     Parameters:
1902                  self - http object
1903              
1904                  Returns:
1905                  OK
1906              */
1907              MI_Result HttpClient_Delete(
1908                  HttpClient* self)
1909              {
1910                  /* Check parameters */
1911                  if (!self)
1912                      return MI_RESULT_INVALID_PARAMETER;
1913              
1914                  /* Check magic number */
1915                  if (self->magic != _MAGIC)
1916 krisbash 1.3     {
1917                      LOGE2((ZT("HttpClient_Delete - Bad magic number")));
1918 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
1919 krisbash 1.3     }
1920 mike     1.1 
1921                  if (self->internalSelectorUsed)
1922                  {
1923                      /* Release selector;
1924 krisbash 1.3         Note: Selector_Destroy closes all sockets in a list including connector and listener */
1925 mike     1.1         Selector_Destroy(self->selector);
1926              
1927                      /* Shutdown the network */
1928                      Sock_Stop();
1929                  }
1930                  else
1931                  {
1932                      /* remove connector from handler */
1933                      if (self->connector)
1934                          Selector_RemoveHandler(self->selector, &self->connector->base);
1935                  }
1936              
1937                  if (self->sslContext)
1938                      SSL_CTX_free(self->sslContext);
1939              
1940                  /* Clear magic number */
1941                  self->magic = 0xDDDDDDDD;
1942              
1943                  /* Free self pointer */
1944 krisbash 1.3     PAL_Free(self);
1945 mike     1.1 
1946                  return MI_RESULT_OK;
1947              }
1948              
1949              
1950 krisbash 1.3 /*
1951 mike     1.1     Sends http request.
1952              
1953                  Parameters:
1954                  self - http object
1955                  uri - request's URI
1956 krisbash 1.3     headers - [opt] extra headers for request.
1957                  data - [opt] content to send. if message is accepted to be sent,
1958 mike     1.1         on return *data == null (taking memory ownership)
1959              
1960                  Returns:
1961                  OK or appropriate error
1962               */
1963              MI_Result HttpClient_StartRequest(
1964                  HttpClient* self,
1965                  const char* verb,
1966                  const char* uri,
1967                  const HttpClientRequestHeaders* headers,
1968                  Page** data)
1969              {
1970 krisbash 1.3     LOGD2((ZT("HttpClient_StartRequest - Begin. verb: %s, URI: %s"), verb, uri));
1971 mike     1.1 
1972                  /* check params */
1973                  if (!self || !uri)
1974                      return MI_RESULT_INVALID_PARAMETER;
1975              
1976                  if (self->magic != _MAGIC)
1977                  {
1978 krisbash 1.3         LOGE2((ZT("HttpClient_Delete - Bad magic number")));
1979                      trace_StartRequest_InvalidMagic();
1980 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
1981                  }
1982              
1983 krisbash 1.3     if (self->connector == NULL)
1984 mike     1.1     {
1985 krisbash 1.3         LOGE2((ZT("HttpClient_Delete - Connection is not open")));
1986                      trace_StartRequest_ConnectionClosed();
1987 mike     1.1         return MI_RESULT_FAILED;
1988                  }
1989              
1990                  /* create header page */
1991                  self->connector->sendHeader =
1992                      _CreateHttpHeader(verb, uri, headers, (data && *data) ? (*data)->u.s.size : 0);
1993 krisbash 1.3 
1994                  if (data != NULL)
1995 mike     1.1     {
1996                      self->connector->sendPage = *data;
1997                      *data = 0;
1998                  }
1999                  else
2000 krisbash 1.3         self->connector->sendPage = NULL;
2001 mike     1.1 
2002                  /* set status to failed, until we know more details */
2003                  self->connector->status = MI_RESULT_FAILED;
2004                  self->connector->sentSize = 0;
2005                  self->connector->sendingState = RECV_STATE_HEADER;
2006                  self->connector->base.mask |= SELECTOR_WRITE;
2007              
2008                  _RequestCallbackWrite(self->connector);
2009              
2010                  return MI_RESULT_OK;
2011              }
2012              
2013              MI_Result HttpClient_Run(
2014                  HttpClient* self,
2015                  MI_Uint64 timeoutUsec)
2016              {
2017                  /* Run the selector */
2018 krisbash 1.3     return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
2019 mike     1.1 }
2020              
2021              MI_Result HttpClient_SetTimeout(
2022                  HttpClient* self,
2023                  MI_Uint64 timeoutUsec)
2024              {
2025                  MI_Uint64 currentTimeUsec = 0;
2026              
2027 krisbash 1.3     PAL_Time(&currentTimeUsec);
2028 mike     1.1 
2029                  /* check params */
2030                  if (!self)
2031                      return MI_RESULT_INVALID_PARAMETER;
2032              
2033                  if (self->magic != _MAGIC)
2034                  {
2035 krisbash 1.3         trace_Timeout_InvalidMagic();
2036 mike     1.1         return MI_RESULT_INVALID_PARAMETER;
2037                  }
2038              
2039                  if (!self->connector)
2040                      return MI_RESULT_INVALID_PARAMETER;
2041              
2042                  /* create header page */
2043                  self->connector->timeoutUsec = timeoutUsec;
2044                  self->connector->base.fireTimeoutAt = currentTimeUsec + self->connector->timeoutUsec;
2045              
2046                  return MI_RESULT_OK;
2047              }

ViewCVS 0.9.2