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

   1 mike  1.1 /*
   2           **==============================================================================
   3           **
   4           ** Open Management Infrastructure (OMI)
   5           **
   6           ** Copyright (c) Microsoft Corporation
   7           ** 
   8           ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
   9           ** use this file except in compliance with the License. You may obtain a copy 
  10           ** of the License at 
  11           **
  12           **     http://www.apache.org/licenses/LICENSE-2.0 
  13           **
  14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15           ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
  16           ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
  17           ** MERCHANTABLITY OR NON-INFRINGEMENT. 
  18           **
  19           ** See the Apache 2 License for the specific language governing permissions 
  20           ** and limitations under the License.
  21           **
  22 mike  1.1 **==============================================================================
  23           */
  24           
  25           #include <assert.h>
  26           #include <ctype.h>
  27           //#include "http.h"
  28           #include "httpclient.h"
  29           #include "addr.h"
  30           #include "sock.h"
  31           #include "selector.h"
  32           #include <base/time.h>
  33           #include <base/buf.h>
  34           #include <base/log.h>
  35           #include <base/result.h>
  36           #include <base/strings.h>
  37           #include <base/io.h>
  38           #include <base/paths.h>
  39           
  40           #ifdef CONFIG_POSIX
  41           #include <openssl/ssl.h>
  42           #include <openssl/err.h>
  43 mike  1.1 #else
  44           /* ssl not supported in this configuration; just make compiler happy */
  45           typedef void SSL;
  46           typedef void SSL_CTX;
  47           #define SSL_CTX_free(c)
  48           #define SSL_new(c) 0
  49           #define SSL_free(c)
  50           #define SSL_set_connect_state(c)
  51           #define SSL_set_fd(c,a) (a==a)
  52           #define SSL_read(c,a,b) 0
  53           #define SSL_write(c,a,b) 0
  54           #define SSL_get_error(c,e) e
  55           #define SSL_ERROR_WANT_WRITE 0
  56           #define SSL_ERROR_WANT_READ 1
  57           #define SSL_ERROR_SYSCALL 2
  58           
  59           #ifdef EWOULDBLOCK
  60           # undef EWOULDBLOCK
  61           #endif
  62           
  63           #define EWOULDBLOCK 0
  64 mike  1.1 
  65           #ifdef EINPROGRESS
  66           # undef EINPROGRESS
  67           #endif 
  68           
  69           #define EINPROGRESS 0
  70           
  71           #define ERR_get_error() 0
  72           #define ERR_error_string_n(c,a,b) a[0]=0
  73           #define SSL_accept(c) 0
  74           #define SSL_connect(c) 0
  75           
  76           #endif
  77           
  78           #define T MI_T
  79           
  80           /* #define ENABLE_TRACING  // */
  81           #ifdef  ENABLE_TRACING
  82           #define PRINTF(a)  TIMESTAMP(); printf a
  83           #define TIMESTAMP() \
  84           {\
  85 mike  1.1         MI_Uint64 currentTimeUsec = 0;\
  86           \
  87                   Time_Now(&currentTimeUsec);\
  88                   currentTimeUsec /= 1000;    /* ms */ \
  89                   printf("%ds%03dms ", (int)(currentTimeUsec / 1000 % 1000), (int)(currentTimeUsec % 1000));\
  90           }
  91           
  92           #define PRINTF_2(a)
  93           #else
  94           #define PRINTF(a)
  95           #define PRINTF_2(a)
  96           #endif
  97           
  98           
  99           
 100           /*
 101           **==============================================================================
 102           **
 103           ** Local definitions:
 104           **
 105           **==============================================================================
 106 mike  1.1 */
 107           
 108           static const MI_Uint32 _MAGIC = 0x5FC7B966;
 109           static const MI_Uint32 MAX_HEADER_SIZE = 2 * 1024;
 110           static const MI_Uint32 INITIAL_BUFFER_SIZE = 2 * 1024;
 111           static const MI_Uint32 DEFAULT_HTTP_TIMEOUT_USEC = 60 * 1000000;
 112           
 113           typedef enum _Http_RecvState
 114           {
 115               RECV_STATE_HEADER,
 116               RECV_STATE_CONTENT,
 117               RECV_STATE_CHUNKHEADER,
 118               RECV_STATE_CHUNKDATA
 119           }
 120           Http_RecvState;
 121           
 122           typedef struct _Http_SR_SocketData
 123           {
 124               /* based member*/
 125               Handler     base;
 126           
 127 mike  1.1     /* timeout */
 128               MI_Uint64   timeoutUsec;
 129           
 130               /* ssl part */
 131               SSL*  ssl;
 132               MI_Boolean  reverseOperations;  /*reverse read/write Events/Handlers*/
 133               MI_Boolean  connectDone;
 134           
 135               /* receiving data */
 136               char*       recvBuffer;
 137               size_t      recvBufferSize;
 138               size_t      recvievedSize;
 139               Http_RecvState      recvingState;
 140               HttpClientHeaderField recvHeaderFields[64];
 141               HttpClientResponseHeader   recvHeaders;
 142               MI_Sint64   contentLength;
 143               Page*   recvPage;
 144           
 145               /* sending part */
 146               Page*   sendPage;
 147               Page*   sendHeader;
 148 mike  1.1     size_t      sentSize;
 149               Http_RecvState  sendingState;
 150           
 151               /* general operation status */
 152               MI_Result status;
 153           
 154           }
 155           Http_SR_SocketData;
 156           
 157           struct _HttpClient
 158           {
 159               MI_Uint32       magic;
 160               Selector        internalSelector;
 161               Selector*       selector;
 162               HttpClientCallbackOnStatus     callbackOnStatus;
 163               HttpClientCallbackOnResponse   callbackOnResponse;
 164               void*                               callbackData;
 165               SSL_CTX*    sslContext;
 166           
 167               Http_SR_SocketData* connector;
 168           
 169 mike  1.1     MI_Boolean  internalSelectorUsed;
 170           };
 171           
 172           
 173           /* helper functions result */
 174           typedef enum _Http_CallbackResult
 175           {
 176               PRT_CONTINUE,
 177               PRT_RETURN_TRUE,
 178               PRT_RETURN_FALSE
 179           }
 180           Http_CallbackResult;
 181           
 182           
 183           MI_INLINE MI_Uint8 _ToLower(MI_Uint8 x)
 184           {
 185               return (MI_Uint8)tolower(x);
 186           }
 187           
 188           #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8)  | (((MI_Uint16)len)) )
 189           
 190 mike  1.1 static MI_Boolean _getNameValuePair(
 191               char ** line,
 192               char ** value,
 193               int*  nameHashCode )
 194           {
 195               int len = 0;
 196               char* p;
 197               /* find name end /hash-code */
 198           
 199               *nameHashCode =  _ToLower((MI_Uint8)(*line)[0])<<16;
 200           
 201               for (len = 1; (*line)[len] != ':' && (*line)[len] != '\r'; len++ )
 202                   ;
 203           
 204               if ((*line)[len] != ':')
 205                   return MI_FALSE;
 206           
 207               *nameHashCode |=  (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
 208               (*line)[len] = 0;
 209               p = *line + len + 1;
 210           
 211 mike  1.1     /* skip spaces in value */
 212               while (p[0] == ' ' || p[0] == '\t')
 213                   p++;
 214           
 215               *value = p;
 216           
 217               /* skip to end of line */
 218               for ( ; ; )
 219               {
 220                   if (p[0] == '\r' && p[1] == '\n' && 
 221                       (p[2] != ' ' && p[2] != '\t') )
 222                   {
 223                       p[0] = 0;
 224                       (*line) = p + 2;
 225                       break;
 226                   }
 227                   p ++;
 228               }
 229           
 230               /* remove trailing spaces */
 231               p--;
 232 mike  1.1     while (p[0] == ' ' || p[0] == '\t')
 233                   p--;
 234           
 235               p[1] = 0;
 236           
 237               return MI_TRUE;
 238           }
 239           
 240           
 241           static MI_Boolean _getHeaderField(
 242               Http_SR_SocketData* handler,
 243               char ** line)
 244           {
 245               /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 246                   Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
 247               */
 248               char* name = *line;
 249               char* value = NULL;
 250               int nameHashCode;
 251           
 252               if (!_getNameValuePair(line, &value, &nameHashCode))
 253 mike  1.1         return MI_FALSE;
 254           
 255           
 256               if (nameHashCode == _HashCode('c','h',14) && /*Content-Length*/
 257                   Strcasecmp(name,"Content-Length") == 0)
 258               {
 259                       handler->contentLength = Strtoull(value, NULL, 10);
 260                       /*if ( handler->contentLength > HTTP_MAX_CONTENT )
 261                           return MI_FALSE;*/
 262               }
 263               else if (nameHashCode == _HashCode('t','g',17) && /*Transfer-Encoding*/
 264                   Strcasecmp(name,"Transfer-Encoding") == 0)
 265               {
 266                       handler->contentLength = -1;
 267               }
 268           
 269               else
 270               {
 271                   if (handler->recvHeaders.sizeHeaders < MI_COUNT(handler->recvHeaderFields))
 272                   {
 273                       handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].name = name;
 274 mike  1.1             handler->recvHeaderFields[handler->recvHeaders.sizeHeaders].value = value;
 275                       handler->recvHeaders.sizeHeaders++;
 276                   }
 277                   else
 278                   {
 279                       LOGW_CHAR(("too many http headers; skipping %s: %s\n", name, value));
 280                   }
 281               }
 282           
 283               return MI_TRUE;
 284           }
 285           
 286           static MI_Boolean _getChunkSize(
 287               const char * line,
 288               MI_Uint32* chunkSize)
 289           {
 290               *chunkSize = 0;
 291           
 292               while(*line)
 293               {
 294                   char c = *line;
 295 mike  1.1 
 296                   if (c >= '0' && c <= '9')
 297                       *chunkSize = *chunkSize * 16 + (c - '0');
 298                   else if (c >= 'a' && c <= 'f')
 299                       *chunkSize = *chunkSize * 16 + (c - 'a' + 10);
 300                   else if (c >= 'A' && c <= 'F')
 301                       *chunkSize = *chunkSize * 16 + (c - 'A' + 10);
 302                   else
 303                       break;
 304           
 305                   line++;
 306               }
 307           
 308               return MI_TRUE;
 309           }
 310           
 311           
 312           static MI_Boolean _getRequestLine(
 313               Http_SR_SocketData* handler,
 314               char ** line)
 315           {
 316 mike  1.1     size_t index;
 317               /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
 318                   Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
 319               */
 320           
 321               /* initialize header */
 322               handler->recvHeaders.sizeHeaders = 0;
 323               handler->recvHeaders.headers = handler->recvHeaderFields;
 324           
 325               /* find http code */
 326               {
 327                   /* skip http version, that is in format
 328                           HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
 329                           http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1
 330           
 331                           Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
 332                   */
 333                   const char* s = *line + 9; /*+ HTTP/1.1<sp>*/
 334           
 335                   handler->recvHeaders.httpError = Strtoul(s, NULL, 10);
 336               }
 337 mike  1.1 
 338               /* skip to end of line */
 339               for ( index = 1; index < handler->recvievedSize; index++ )
 340               {
 341                   if ((*line)[index-1] == '\r' && (*line)[index] == '\n' )
 342                   {
 343                       (*line) = (*line) + index + 1;
 344                       return MI_TRUE;
 345                   }
 346               }
 347           
 348               return MI_FALSE;
 349           }
 350           
 351           static MI_Result _Sock_Read(
 352               Http_SR_SocketData* handler,
 353               void* buf,
 354               size_t buf_size,
 355               size_t* sizeRead)
 356           {
 357               int res;
 358 mike  1.1 
 359               if (!handler->ssl)
 360                   return Sock_Read(handler->base.sock, buf, buf_size, sizeRead);
 361           
 362               handler->base.mask &= ~SELECTOR_WRITE;
 363               handler->base.mask |= SELECTOR_READ;
 364               handler->reverseOperations = MI_FALSE;
 365           
 366               *sizeRead = 0;
 367           
 368               res = SSL_read(handler->ssl, buf, buf_size);
 369               PRINTF(("ssl read %d\n", res));
 370           
 371               if ( res == 0 )
 372                   return MI_RESULT_OK;    /* connection closed */
 373           
 374               if ( res > 0 )
 375               {
 376                   *sizeRead = res;
 377                   return MI_RESULT_OK;    /* ok */
 378               }
 379 mike  1.1 
 380               switch (SSL_get_error(handler->ssl, res))
 381               {
 382               case SSL_ERROR_WANT_WRITE:
 383                   handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 384                   handler->base.mask &= ~SELECTOR_READ;
 385                   handler->base.mask |= SELECTOR_WRITE;
 386                   PRINTF(("ssl read/accept WANT_WRITE\n"));
 387                   return MI_RESULT_WOULD_BLOCK;
 388           
 389               case SSL_ERROR_WANT_READ:
 390                   PRINTF(("ssl read/accept WANT_READ\n"));
 391                   return MI_RESULT_WOULD_BLOCK;
 392           
 393               case SSL_ERROR_SYSCALL:
 394                   if (EAGAIN == errno ||
 395                       EWOULDBLOCK == errno ||
 396                       EINPROGRESS == errno)
 397                       return MI_RESULT_WOULD_BLOCK;
 398           
 399                   LOGW_CHAR(("ssl-read: unexpected sys error %d\n", errno));
 400 mike  1.1         break;
 401           
 402               default:
 403                   {
 404                       /* print error */
 405                       unsigned long err = ERR_get_error();
 406                       while (err)
 407                       {
 408                           char err_txt[200];
 409                           ERR_error_string_n(err, err_txt, sizeof(err_txt));
 410           
 411                           LOGW_CHAR(("ssl-read error: %d [%s]\n", (int)err, err_txt));
 412           
 413                           err = ERR_get_error();
 414                       }
 415                   }
 416                   break;
 417               }
 418               return MI_RESULT_FAILED;
 419           }
 420           
 421 mike  1.1 static MI_Result _Sock_Write(
 422               Http_SR_SocketData* handler,
 423               void* buf,
 424               size_t buf_size,
 425               size_t* sizeWritten)
 426           {
 427               int res;
 428           
 429               if (!handler->ssl)
 430                   return Sock_Write(handler->base.sock, buf, buf_size, sizeWritten);
 431           
 432               /* Do not clear READ flag, since 'close' notification
 433               delivered as READ event */
 434               handler->base.mask &= ~SELECTOR_READ; 
 435               handler->base.mask |= SELECTOR_WRITE;
 436               handler->reverseOperations = MI_FALSE;
 437           
 438               *sizeWritten = 0;
 439           
 440               if (handler->connectDone)
 441               {
 442 mike  1.1         res = SSL_write(handler->ssl, buf, buf_size);
 443                   PRINTF(("ssl write %d\n", res));
 444               }
 445               else
 446               {
 447                   res = SSL_connect(handler->ssl);
 448                   PRINTF(("ssl connect %d\n", res));
 449                   if ( res > 0 )
 450                   {
 451                       /* we are done with accpet */
 452                       handler->connectDone = MI_TRUE;
 453                       return _Sock_Write(handler,buf,buf_size,sizeWritten);
 454                   }
 455                   /* perform regular error checking */
 456               }
 457           
 458           
 459               if ( res == 0 )
 460                   return MI_RESULT_OK;    /* connection closed */
 461           
 462               if ( res > 0 )
 463 mike  1.1     {
 464                   *sizeWritten = res;
 465                   return MI_RESULT_OK;    /* ok */
 466               }
 467           
 468               switch (SSL_get_error(handler->ssl, res))
 469               {
 470               case SSL_ERROR_WANT_WRITE:
 471                   PRINTF(("ssl write/connetc WANT_WRITE\n"));
 472                   return MI_RESULT_WOULD_BLOCK;
 473           
 474               case SSL_ERROR_WANT_READ:
 475                   PRINTF(("ssl write/connetc WANT_READ\n"));
 476                   handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
 477                   handler->base.mask |= SELECTOR_READ;
 478                   handler->base.mask &= ~SELECTOR_WRITE; 
 479                   return MI_RESULT_WOULD_BLOCK;
 480           
 481               case SSL_ERROR_SYSCALL:
 482                   if (EAGAIN == errno ||
 483                       EWOULDBLOCK == errno ||
 484 mike  1.1             EINPROGRESS == errno)
 485                       return MI_RESULT_WOULD_BLOCK;
 486           
 487                   LOGW_CHAR(("ssl-write: unexpected sys error %d\n", errno));
 488                   break;
 489           
 490               default:
 491                   break;
 492               }
 493               return MI_RESULT_FAILED;
 494           }
 495           
 496           static Http_CallbackResult _ReadHeader(
 497               Http_SR_SocketData* handler)
 498           {
 499               char* buf;
 500               char* currentLine;
 501               char* data;
 502               size_t buf_size, received, index;
 503               MI_Result r;
 504               MI_Boolean fullHeaderReceived = MI_FALSE;
 505 mike  1.1 
 506               /* are we done with header? */
 507               if (handler->recvingState != RECV_STATE_HEADER)
 508                   return PRT_CONTINUE;
 509           
 510               buf = handler->recvBuffer + handler->recvievedSize;
 511               buf_size = handler->recvBufferSize - handler->recvievedSize;
 512               received = 0;
 513           
 514               r = _Sock_Read(handler, buf, buf_size, &received);
 515               PRINTF(("%d: read r = %d, recv = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)received, (int)handler->reverseOperations ));
 516           
 517               if ( r == MI_RESULT_OK && 0 == received )
 518                   return PRT_RETURN_FALSE; /* conection closed */
 519           
 520               if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 521                   return PRT_RETURN_FALSE;
 522           
 523               if (!received)
 524                   return PRT_RETURN_TRUE;
 525           
 526 mike  1.1     handler->recvievedSize += received;
 527           
 528               /* check header */
 529               PRINTF_2(("%s\n",buf));
 530           
 531               /* did we get full header? */
 532               buf = handler->recvBuffer;
 533               for ( index = 3; index < handler->recvievedSize; index++ )
 534               {
 535                   if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
 536                       buf[index-2] == '\n' && buf[index] == '\n' )
 537                   {
 538                       fullHeaderReceived = MI_TRUE;
 539                       break;
 540                   }
 541               }
 542           
 543               if (!fullHeaderReceived )
 544               {
 545                   if ( handler->recvievedSize <  handler->recvBufferSize )
 546                       return PRT_RETURN_TRUE; /* continue reading */
 547 mike  1.1 
 548                   if ( handler->recvBufferSize < MAX_HEADER_SIZE )
 549                   {
 550                       buf = realloc(handler->recvBuffer, handler->recvBufferSize * 2);
 551           
 552                       if (!buf)
 553                           return PRT_RETURN_FALSE;
 554           
 555                       handler->recvBufferSize *= 2;
 556                       handler->recvBuffer = buf;
 557                       return _ReadHeader(handler);
 558                   }
 559                   else
 560                   {
 561                       /* http header is too big - drop connection */
 562                       LOGW((T("http header is too big; dropping connection\n")));
 563                       return PRT_RETURN_FALSE;
 564                   }
 565               }
 566           
 567               /* consume data */
 568 mike  1.1     currentLine = buf;
 569               data = buf + index + 1; /* pointer to data in case we got some */
 570           
 571               if (!_getRequestLine(handler, &currentLine))
 572                   return PRT_RETURN_FALSE;
 573           
 574           
 575               while ((data-currentLine) > 3)
 576               {
 577                   if (!_getHeaderField(handler, &currentLine))
 578                       return PRT_RETURN_FALSE;
 579           
 580               }
 581           
 582               /* Check if we have to deal with chunked-encoded data */
 583               if (handler->contentLength < 0)
 584               {
 585                   handler->recvievedSize -= index + 1;
 586           
 587                   /* Invoke user's callback with header information */
 588                   {
 589 mike  1.1             HttpClient* self = (HttpClient*)handler->base.data;
 590           
 591                       if (!(*self->callbackOnResponse)( self, self->callbackData, &handler->recvHeaders, 
 592                           handler->contentLength, handler->contentLength == 0, 0))
 593                           return PRT_RETURN_FALSE;
 594                   }
 595           
 596                   /* remove consumed header part */
 597                   memmove(handler->recvBuffer, data, handler->recvievedSize);
 598           
 599                   handler->recvingState = RECV_STATE_CHUNKHEADER;
 600                   return PRT_CONTINUE;
 601               }
 602           
 603               /* Allocate zero-terminated buffer */
 604               handler->recvPage = (Page*)malloc(sizeof(Page) + (size_t)handler->contentLength + 1);
 605           
 606               if (!handler->recvPage)
 607                   return PRT_RETURN_FALSE;
 608           
 609               ((char*)(handler->recvPage + 1))[handler->contentLength] = 0;
 610 mike  1.1 
 611               handler->recvPage->u.s.size = (unsigned int)handler->contentLength;
 612               handler->recvPage->u.s.next = 0;
 613           
 614               handler->recvievedSize -= index + 1;
 615           
 616               /* Verify that we have not more than 'content-length' bytes in buffer left 
 617                   If we have more, assuming http client is invalid and drop connection */
 618               if (handler->recvievedSize > (size_t)handler->contentLength)
 619               {
 620                   LOGW((T("http payload is bigger than content-length\n")));
 621                   return PRT_RETURN_FALSE;
 622               }
 623           
 624               memcpy( handler->recvPage + 1, data, handler->recvievedSize );
 625               handler->recvingState = RECV_STATE_CONTENT;
 626           
 627               PRINTF_2(("full header read; page size %d, position %d\n", handler->recvPage->u.s.size, handler->recvievedSize));
 628           
 629               /* Invoke user's callback with header information */
 630               {
 631 mike  1.1         HttpClient* self = (HttpClient*)handler->base.data;
 632           
 633                   if (!(*self->callbackOnResponse)( self, self->callbackData, &handler->recvHeaders, 
 634                       handler->contentLength, handler->contentLength == 0, 0))
 635                       return PRT_RETURN_FALSE;
 636               }
 637           
 638               return PRT_CONTINUE;
 639           }
 640           
 641           static Http_CallbackResult _ReadData(
 642               Http_SR_SocketData* handler)
 643           {
 644               //HttpClient* self = (HttpClient*)handler->base.data;
 645               char* buf;
 646               size_t buf_size, received;
 647               MI_Result r;
 648           
 649               /* are we in the right state? */
 650               if (handler->recvingState != RECV_STATE_CONTENT)
 651                   return PRT_RETURN_FALSE;
 652 mike  1.1 
 653               buf = ((char*)(handler->recvPage + 1)) + handler->recvievedSize;
 654               buf_size = (size_t)(handler->contentLength - handler->recvievedSize);
 655               received = 0;
 656           
 657               if (buf_size)
 658               {
 659                   r = _Sock_Read(handler, buf, buf_size, &received);
 660           
 661                   PRINTF(("%d: read r = %d, recv = %d\n", (int)handler->base.sock, (int)r, (int)received ));
 662           
 663                   if ( r == MI_RESULT_OK && 0 == received )
 664                       return PRT_RETURN_FALSE; /* conection closed */
 665           
 666                   if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 667                       return PRT_RETURN_FALSE;
 668           
 669                   handler->recvievedSize += received;
 670               }
 671           
 672               /* did we get all data? */
 673 mike  1.1     PRINTF_2(("dt status - %d / %d\n", (int)handler->recvievedSize, (int)handler->contentLength));
 674           
 675               if ( handler->recvievedSize != (size_t)handler->contentLength )
 676                   return PRT_RETURN_TRUE;
 677            
 678               /* Invoke user's callback with header information */
 679               {
 680                   HttpClient* self = (HttpClient*)handler->base.data;
 681           
 682                   if (!(*self->callbackOnResponse)( self, self->callbackData, 0, 
 683                       handler->contentLength, MI_TRUE, &handler->recvPage))
 684                       return PRT_RETURN_FALSE;
 685           
 686                   /* status callback */
 687                   handler->status = MI_RESULT_OK;
 688                   (*self->callbackOnStatus)(
 689                       self, 
 690                       self->callbackData, 
 691                       MI_RESULT_OK );
 692               }
 693           
 694 mike  1.1 
 695               if (handler->recvPage)
 696                   free(handler->recvPage);
 697           
 698               handler->recvPage = 0;
 699               handler->recvievedSize = 0;
 700               memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 701               handler->recvingState = RECV_STATE_HEADER;
 702               return PRT_CONTINUE;
 703           }
 704           
 705           
 706           static Http_CallbackResult _ReadChunkHeader(
 707               Http_SR_SocketData* handler)
 708           {
 709               char* buf;
 710               char* currentLine;
 711               char* data;
 712               size_t buf_size, received, index;
 713               MI_Result r;
 714               MI_Boolean fullHeaderReceived = MI_FALSE;
 715 mike  1.1     MI_Uint32   chunkSize = 0;
 716               MI_Boolean connectionClosed = MI_FALSE;
 717           
 718               /* are we done with header? */
 719               if (handler->recvingState != RECV_STATE_CHUNKHEADER)
 720                   return PRT_CONTINUE;
 721           
 722               buf = handler->recvBuffer + handler->recvievedSize;
 723               buf_size = handler->recvBufferSize - handler->recvievedSize;
 724               received = 0;
 725           
 726               r = _Sock_Read(handler, buf, buf_size, &received);
 727               PRINTF(("%d: read r = %d, recv = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)received, (int)handler->reverseOperations ));
 728           
 729               if ( r == MI_RESULT_OK && 0 == received )
 730               {
 731                   if (!handler->recvBufferSize)
 732                       return PRT_RETURN_FALSE; /* conection closed */
 733           
 734                   connectionClosed = MI_TRUE;
 735               }
 736 mike  1.1 
 737               if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 738                   return PRT_RETURN_FALSE;
 739           
 740               if (!received && !handler->recvBufferSize)
 741                   return PRT_RETURN_TRUE;
 742           
 743               handler->recvievedSize += received;
 744           
 745               /* check header */
 746               PRINTF_2(("%s\n",buf));
 747           
 748               /* did we get full header? */
 749               buf = handler->recvBuffer;
 750               for ( index = 1; index < handler->recvievedSize; index++ )
 751               {
 752                   if (buf[index-1] == '\r' && buf[index] == '\n' )
 753                   {
 754                       fullHeaderReceived = MI_TRUE;
 755                       break;
 756                   }
 757 mike  1.1     }
 758           
 759               if (!fullHeaderReceived )
 760               {
 761                   if (connectionClosed)
 762                       return PRT_RETURN_FALSE; /* conection closed */
 763           
 764                   if ( handler->recvievedSize <  handler->recvBufferSize )
 765                       return PRT_RETURN_TRUE; /* continue reading */
 766           
 767                   if ( handler->recvBufferSize < MAX_HEADER_SIZE )
 768                   {
 769                       buf = realloc(handler->recvBuffer, handler->recvBufferSize * 2);
 770           
 771                       if (!buf)
 772                           return PRT_RETURN_FALSE;
 773           
 774                       handler->recvBufferSize *= 2;
 775                       handler->recvBuffer = buf;
 776                       return _ReadChunkHeader(handler);
 777                   }
 778 mike  1.1         else
 779                   {
 780                       /* http chunk header is too big - drop connection */
 781                       LOGW((T("http chunk header is too big; dropping connection\n")));
 782                       return PRT_RETURN_FALSE;
 783                   }
 784               }
 785           
 786               /* consume data */
 787               currentLine = buf;
 788               data = buf + index + 1; /* pointer to data in case we got some */
 789           
 790               if (!_getChunkSize(currentLine, &chunkSize))
 791                   return PRT_RETURN_FALSE;
 792           
 793               if (0 == chunkSize)
 794               {
 795                   /* last chunk received */
 796           
 797                   /* Invoke user's callback with header information */
 798                   {
 799 mike  1.1             HttpClient* self = (HttpClient*)handler->base.data;
 800           
 801                       if (!(*self->callbackOnResponse)( self, self->callbackData, 0, 
 802                           handler->contentLength, MI_TRUE, 0))
 803                           return PRT_RETURN_FALSE;
 804           
 805                       /* status callback */
 806                       handler->status = MI_RESULT_OK;
 807                       (*self->callbackOnStatus)(
 808                           self, 
 809                           self->callbackData, 
 810                           MI_RESULT_OK );
 811                   }
 812           
 813                   /* clean up state */
 814                   handler->recvPage = 0;
 815                   handler->recvievedSize = 0;
 816                   memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 817                   handler->recvingState = RECV_STATE_HEADER;
 818           
 819                   if (connectionClosed)
 820 mike  1.1             return PRT_RETURN_FALSE; /* conection closed */
 821           
 822                   return PRT_CONTINUE;
 823               }
 824           
 825               /* Allocate zero-terminated buffer */
 826               handler->recvPage = (Page*)malloc(sizeof(Page) + (size_t)chunkSize + 2 /*CR-LF*/ + 1 /* \0 */);
 827           
 828               if (!handler->recvPage)
 829                   return PRT_RETURN_FALSE;
 830           
 831               ((char*)(handler->recvPage + 1))[chunkSize+2] = 0;
 832           
 833               handler->recvPage->u.s.size = (unsigned int)chunkSize;
 834               handler->recvPage->u.s.next = 0;
 835           
 836               /* subtract header size */
 837               handler->recvievedSize -= index + 1;
 838           
 839               /* in case of small chunks we may receive more than one chunk already */
 840               if (handler->recvievedSize > (size_t)(chunkSize+2))
 841 mike  1.1     {
 842                   /* copy page size to page */
 843                   memcpy( handler->recvPage + 1, data, chunkSize+2 );
 844           
 845                   /* notify user */
 846                   {
 847                       HttpClient* self = (HttpClient*)handler->base.data;
 848           
 849                       if (!(*self->callbackOnResponse)( self, self->callbackData, 0, 
 850                           handler->contentLength, MI_FALSE, &handler->recvPage))
 851                           return PRT_RETURN_FALSE;
 852           
 853                       if (handler->recvPage)
 854                           free(handler->recvPage);
 855           
 856                       handler->recvPage = 0;
 857                   }
 858           
 859                   /* remove consumed part */
 860                   memmove(handler->recvBuffer, data + chunkSize+2, handler->recvievedSize - (chunkSize+2));
 861                   handler->recvievedSize -= (chunkSize+2);
 862 mike  1.1 
 863                   /* consume next chunk */
 864                   return _ReadChunkHeader(handler);
 865               }
 866           
 867               memcpy( handler->recvPage + 1, data, handler->recvievedSize );
 868               handler->recvingState = RECV_STATE_CHUNKDATA;
 869           
 870               if (connectionClosed)
 871                   return PRT_RETURN_FALSE; /* conection closed */
 872           
 873               return PRT_CONTINUE;
 874           }
 875           static Http_CallbackResult _ReadChunkData(
 876               Http_SR_SocketData* handler)
 877           {
 878               //HttpClient* self = (HttpClient*)handler->base.data;
 879               char* buf;
 880               size_t buf_size, received;
 881               MI_Result r;
 882           
 883 mike  1.1     /* are we in the right state? */
 884               if (handler->recvingState != RECV_STATE_CHUNKDATA)
 885                   return PRT_RETURN_FALSE;
 886           
 887               buf = ((char*)(handler->recvPage + 1)) + handler->recvievedSize;
 888               buf_size = (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */ - handler->recvievedSize);
 889               received = 0;
 890           
 891               if (buf_size)
 892               {
 893                   r = _Sock_Read(handler, buf, buf_size, &received);
 894           
 895                   PRINTF(("%d: read r = %d, recv = %d\n", (int)handler->base.sock, (int)r, (int)received ));
 896           
 897                   if ( r == MI_RESULT_OK && 0 == received )
 898                       return PRT_RETURN_FALSE; /* conection closed */
 899           
 900                   if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 901                       return PRT_RETURN_FALSE;
 902           
 903                   handler->recvievedSize += received;
 904 mike  1.1     }
 905           
 906               /* did we get all data? */
 907               PRINTF_2(("dt status - %d / %d\n", (int)handler->recvievedSize, (int)handler->contentLength));
 908           
 909               if ( handler->recvievedSize != (size_t)(handler->recvPage->u.s.size + 2 /* CR-LF */) )
 910                   return PRT_RETURN_TRUE;
 911            
 912               /* Invoke user's callback with header information */
 913               {
 914                   HttpClient* self = (HttpClient*)handler->base.data;
 915           
 916                   if (!(*self->callbackOnResponse)( self, self->callbackData, 0, 
 917                       handler->contentLength, MI_FALSE, &handler->recvPage))
 918                       return PRT_RETURN_FALSE;
 919           
 920               }
 921           
 922           
 923               if (handler->recvPage)
 924                   free(handler->recvPage);
 925 mike  1.1 
 926               handler->recvPage = 0;
 927               handler->recvievedSize = 0;
 928               memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
 929               handler->recvingState = RECV_STATE_CHUNKHEADER;
 930               return PRT_CONTINUE;
 931           }
 932           
 933           
 934           static Http_CallbackResult _WriteHeader(
 935               Http_SR_SocketData* handler)
 936           {
 937               char* buf;
 938               size_t buf_size, sent;
 939               MI_Result r;
 940           
 941               /* Do we have any data to send? */
 942               if (!handler->sendHeader)
 943                   return PRT_RETURN_TRUE;
 944           
 945               /* are we done with header? */
 946 mike  1.1     if (handler->sendingState == RECV_STATE_CONTENT)
 947                   return PRT_CONTINUE;
 948           
 949               buf = ((char*)(handler->sendHeader + 1)) + handler->sentSize;
 950               buf_size = handler->sendHeader->u.s.size - handler->sentSize;
 951               sent = 0;
 952           
 953               r = _Sock_Write(handler, buf, buf_size, &sent);
 954           
 955               PRINTF(("%d: write r = %d, sent = %d\n", (int)handler->base.sock, (int)r, (int)sent ));
 956           
 957               if ( r == MI_RESULT_OK && 0 == sent )
 958                   return PRT_RETURN_FALSE; /* conection closed */
 959           
 960               if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
 961                   return PRT_RETURN_FALSE;
 962           
 963               handler->sentSize += sent;
 964           
 965               /* did we get all data? */
 966           
 967 mike  1.1     if ( handler->sentSize != handler->sendHeader->u.s.size )
 968                   return PRT_RETURN_TRUE;
 969            
 970               free(handler->sendHeader);
 971               handler->sendHeader = 0;
 972               handler->sentSize = 0;
 973               handler->sendingState = RECV_STATE_CONTENT;
 974           
 975               return PRT_CONTINUE;
 976           }
 977           
 978           static Http_CallbackResult _WriteData(
 979               Http_SR_SocketData* handler)
 980           {
 981               char* buf;
 982               size_t buf_size, sent;
 983               MI_Result r;
 984           
 985               /* are we in the right state? */
 986               if (handler->sendingState != RECV_STATE_CONTENT)
 987                   return PRT_RETURN_FALSE;
 988 mike  1.1 
 989               if (!handler->sendPage)
 990               {   /* no content*/
 991                   handler->sentSize = 0;
 992                   handler->sendingState = RECV_STATE_HEADER;
 993                   handler->base.mask &= ~SELECTOR_WRITE;
 994                   handler->base.mask |= SELECTOR_READ;
 995           
 996                   return PRT_CONTINUE;
 997               }
 998           
 999               buf = ((char*)(handler->sendPage + 1)) + handler->sentSize;
1000               buf_size = handler->sendPage->u.s.size - handler->sentSize;
1001               sent = 0;
1002           
1003               r = _Sock_Write(handler, buf, buf_size, &sent);
1004           
1005               PRINTF(("%d: write r = %d, sent = %d\n", (int)handler->base.sock, (int)r, (int)sent ));
1006           
1007               if ( r == MI_RESULT_OK && 0 == sent )
1008                   return PRT_RETURN_FALSE; /* conection closed */
1009 mike  1.1 
1010               if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
1011                   return PRT_RETURN_FALSE;
1012           
1013               handler->sentSize += sent;
1014           
1015               /* did we get all data? */
1016           
1017               if ( handler->sentSize != handler->sendPage->u.s.size )
1018                   return PRT_RETURN_TRUE;
1019            
1020               free(handler->sendPage);
1021               handler->sendPage = 0;
1022               handler->sentSize = 0;
1023               handler->sendingState = RECV_STATE_HEADER;
1024               handler->base.mask &= ~SELECTOR_WRITE;
1025               handler->base.mask |= SELECTOR_READ;
1026           
1027               return PRT_CONTINUE;
1028           }
1029           
1030 mike  1.1 
1031           static MI_Boolean _RequestCallbackRead(
1032               Http_SR_SocketData* handler)
1033           {
1034               switch (_ReadHeader(handler))
1035               {
1036               case PRT_CONTINUE: break;
1037               case PRT_RETURN_TRUE: return MI_TRUE;
1038               case PRT_RETURN_FALSE: return MI_FALSE;
1039               }
1040           
1041               if (handler->recvingState == RECV_STATE_CONTENT)
1042               {
1043                   switch (_ReadData(handler))
1044                   {
1045                   case PRT_CONTINUE: break;
1046                   case PRT_RETURN_TRUE: return MI_TRUE;
1047                   case PRT_RETURN_FALSE: return MI_FALSE;
1048                   }
1049               }
1050           
1051 mike  1.1     if (handler->recvingState == RECV_STATE_CHUNKHEADER)
1052               {
1053                   switch (_ReadChunkHeader(handler))
1054                   {
1055                   case PRT_CONTINUE: break;
1056                   case PRT_RETURN_TRUE: return MI_TRUE;
1057                   case PRT_RETURN_FALSE: return MI_FALSE;
1058                   }
1059               }
1060               if (handler->recvingState == RECV_STATE_CHUNKDATA)
1061               {
1062                   switch (_ReadChunkData(handler))
1063                   {
1064                   case PRT_CONTINUE: break;
1065                   case PRT_RETURN_TRUE: return MI_TRUE;
1066                   case PRT_RETURN_FALSE: return MI_FALSE;
1067                   }
1068               }
1069           
1070               return MI_TRUE;
1071           }
1072 mike  1.1 
1073           static MI_Boolean _RequestCallbackWrite(
1074               Http_SR_SocketData* handler)
1075           {
1076               switch (_WriteHeader(handler))
1077               {
1078               case PRT_CONTINUE: break;
1079               case PRT_RETURN_TRUE: return MI_TRUE;
1080               case PRT_RETURN_FALSE: return MI_FALSE;
1081               }
1082           
1083               switch (_WriteData(handler))
1084               {
1085               case PRT_CONTINUE: break;
1086               case PRT_RETURN_TRUE: return MI_TRUE;
1087               case PRT_RETURN_FALSE: return MI_FALSE;
1088               }
1089               return MI_TRUE;
1090           }
1091           
1092           
1093 mike  1.1 static MI_Boolean _RequestCallback(
1094               Selector* sel,
1095               Handler* handlerIn,
1096               MI_Uint32 mask, 
1097               MI_Uint64 currentTimeUsec)
1098           {
1099               Http_SR_SocketData* handler = (Http_SR_SocketData*)handlerIn;
1100               sel=sel;
1101           
1102               if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
1103                   ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )
1104               {
1105                   if (!_RequestCallbackRead(handler))
1106                       return MI_FALSE;
1107               }
1108           
1109               if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
1110                   ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )
1111               {
1112                   if (!_RequestCallbackWrite(handler))
1113                       return MI_FALSE;
1114 mike  1.1     }
1115               
1116               /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
1117               if (mask & (SELECTOR_READ | SELECTOR_WRITE))
1118               {
1119                   handler->base.fireTimeoutAt = currentTimeUsec + handler->timeoutUsec;
1120               }
1121           
1122               /* Close conenction by timeout */
1123               if (mask & SELECTOR_TIMEOUT)
1124               {
1125                   if (MI_RESULT_OK != handler->status)
1126                       handler->status = MI_RESULT_TIME_OUT;
1127           
1128                   return MI_FALSE;
1129               }
1130           
1131               if ((mask & SELECTOR_REMOVE) != 0 ||
1132                   (mask & SELECTOR_DESTROY) != 0)
1133               {
1134                   HttpClient* self = (HttpClient*)handler->base.data;
1135 mike  1.1 
1136                   /* notify next stack layer */
1137                   if (MI_RESULT_OK != handler->status)
1138                       (*self->callbackOnStatus)(
1139                           self, 
1140                           self->callbackData, 
1141                           handler->status);
1142           
1143                   self->connector = 0;
1144           
1145                   if (handler->ssl)
1146                       SSL_free(handler->ssl);
1147           
1148                   PRINTF(("%d: close\n", (int)handler->base.sock));
1149           
1150                   Sock_Close(handler->base.sock);
1151           
1152                   if (handler->recvPage)
1153                       free(handler->recvPage);
1154           
1155                   if (handler->sendPage)
1156 mike  1.1             free(handler->sendPage);
1157           
1158                   if (handler->sendHeader)
1159                       free(handler->sendHeader);
1160           
1161                   free(handler->recvBuffer);
1162                   free(handler);
1163               }
1164           
1165               return MI_TRUE;
1166           }
1167           
1168           #ifdef CONFIG_POSIX
1169           static MI_Result _CreateSSLContext(HttpClient* self)
1170           {
1171               SSL_CTX * sslContext = 0;
1172           
1173               sslContext = SSL_CTX_new(SSLv23_method());
1174           
1175               if (!sslContext)
1176               {
1177 mike  1.1         LOGE_CHAR((
1178                       "---> SSL: cannot create ssl context"));
1179                   return MI_RESULT_FAILED;
1180               }
1181               SSL_CTX_set_quiet_shutdown(sslContext, 1);
1182               SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
1183               SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
1184               SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
1185           #if 0
1186               /* Check if there is a certificate file (file containing server
1187               ** certificate) specified. If specified, validate and load the
1188               ** certificate.
1189               */
1190               {
1191                   /* load the specified server certificates */
1192                   LOGI_CHAR(("---> SSL: Loading server certificate from: %s", 
1193                       GetPath(ID_PEMFILE)));
1194           
1195                   if (SSL_CTX_use_certificate_file(sslContext,
1196                       GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)
1197                   {
1198 mike  1.1             LOGE_CHAR(("---> SSL: No server certificate found in %s", 
1199                           GetPath(ID_PEMFILE)));
1200                       SSL_CTX_free(sslContext);
1201                       return MI_RESULT_FAILED;
1202                   }
1203               }
1204           
1205               /*
1206               ** Check if there is a key file (file containing server
1207               ** private key) specified and the key was not already loaded.
1208               ** If specified, validate and load the key.
1209               */
1210               {
1211                   /* load the specified server certificates */
1212                   LOGI_CHAR(("---> SSL: Loading certificate's private key from: %s",
1213                       GetPath(ID_KEYFILE)));
1214           
1215                   //
1216                   // load given private key and check for validity
1217                   //
1218                   if (!_verifyPrivateKey(sslContext, GetPath(ID_KEYFILE)))
1219 mike  1.1         {
1220                       LOGE_CHAR((
1221                           "---> SSL: No server certificate found in %s",
1222                           GetPath(ID_KEYFILE)));
1223                       SSL_CTX_free(sslContext);
1224                       return MI_RESULT_FAILED;
1225                   }
1226               }
1227           #endif
1228               self->sslContext = sslContext;
1229               return MI_RESULT_OK;
1230           }
1231           #endif
1232           
1233           static MI_Result _CreateConnectorSocket(
1234               HttpClient* self,
1235               const char* host,
1236               unsigned short port,
1237               MI_Boolean secure)
1238           {
1239               Addr addr;
1240 mike  1.1     MI_Result r;
1241               Sock s;
1242               Http_SR_SocketData* h;
1243               MI_Uint64 currentTimeUsec;
1244           
1245               /* timeout calculation */
1246               if (MI_RESULT_OK != Time_Now(&currentTimeUsec))
1247                   return MI_RESULT_FAILED;
1248           
1249               // Initialize address.
1250               r = Addr_Init(&addr, host, port);
1251               if (r != MI_RESULT_OK)
1252                   return MI_RESULT_FAILED;
1253           
1254               // Create client socket.
1255               r = Sock_Create(&s);
1256               if (r != MI_RESULT_OK)
1257               {
1258                   Sock_Close(s);
1259                   return MI_RESULT_FAILED;
1260               }
1261 mike  1.1 
1262               r = Sock_SetBlocking(s, MI_FALSE);
1263               if (r != MI_RESULT_OK)
1264               {
1265                   Sock_Close(s);
1266                   return MI_RESULT_FAILED;
1267               }
1268           
1269               // Connect to the server.
1270               r = Sock_Connect(s, &addr);
1271               if (r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK)
1272               {
1273                   Sock_Close(s);
1274                   return MI_RESULT_FAILED;
1275               }
1276           
1277               /* Create handler */
1278               h = (Http_SR_SocketData*)calloc(1, sizeof(Http_SR_SocketData));
1279           
1280               if (!h)
1281               {
1282 mike  1.1         Sock_Close(s);
1283                   return MI_RESULT_FAILED;
1284               }
1285           
1286               h->recvBufferSize = INITIAL_BUFFER_SIZE;
1287               h->recvBuffer = (char*)calloc(1, h->recvBufferSize);
1288               if (!h->recvBuffer)
1289               {
1290                   free(h);
1291                   Sock_Close(s);
1292                   return MI_RESULT_FAILED;
1293               }
1294           
1295               h->base.sock = s;
1296               h->base.mask = SELECTOR_EXCEPTION;
1297               h->base.callback = _RequestCallback;
1298               h->base.data = self;
1299               h->timeoutUsec = DEFAULT_HTTP_TIMEOUT_USEC;
1300               h->base.fireTimeoutAt = currentTimeUsec + h->timeoutUsec;
1301           
1302               /* ssl support */
1303 mike  1.1     if (secure)
1304               {
1305                   h->ssl = SSL_new(self->sslContext);
1306           
1307                   if (!h->ssl)
1308                   {
1309                       LOGW((T("ssl_new() failed\n")));
1310                       free(h);
1311                       Sock_Close(s);
1312                       return MI_RESULT_FAILED;
1313                   }
1314           
1315                   if (!(SSL_set_fd(h->ssl, s) ))
1316                   {
1317                       LOGW((T("ssl_set_fd() failed\n")));
1318                       SSL_free(h->ssl);
1319                       free(h);
1320                       Sock_Close(s);
1321                       return MI_RESULT_FAILED;
1322                   }
1323           
1324 mike  1.1         SSL_set_connect_state(h->ssl);
1325               }
1326           
1327               /* Watch for read events on the incoming connection */
1328               r = Selector_AddHandler(self->selector, &h->base);
1329           
1330               if (r != MI_RESULT_OK)
1331               {
1332                   LOGW((T("Selector_AddHandler() failed\n")));
1333                   if (secure)
1334                       SSL_free(h->ssl);
1335                   free(h);
1336                   Sock_Close(s);
1337                   return MI_RESULT_FAILED;
1338               }
1339           
1340               self->connector = h;
1341           
1342               return MI_RESULT_OK;
1343           }
1344           
1345 mike  1.1 
1346           static MI_Result _New_Http(
1347               HttpClient** selfOut,
1348               Selector* selector, /*optional, maybe NULL*/
1349               HttpClientCallbackOnStatus statusCallback,
1350               HttpClientCallbackOnResponse  responseCallback,
1351               void* callbackData)
1352           {
1353               HttpClient* self;
1354           
1355               /* Check parameters */
1356               if (!selfOut)
1357                   return MI_RESULT_INVALID_PARAMETER;
1358           
1359               /* Clear output parameter */
1360               *selfOut = NULL;
1361           
1362               /* Allocate structure */
1363               {
1364                   self = (HttpClient*)calloc(1, sizeof(HttpClient));
1365           
1366 mike  1.1         if (!self)
1367                       return MI_RESULT_FAILED;
1368               }
1369           
1370               if (selector)
1371               {   /* attach the exisiting selector */
1372                   self->selector = selector;
1373                   self->internalSelectorUsed = MI_FALSE;
1374               }
1375               else
1376               {   /* creaet a new selector */
1377                   /* Initialize the network */
1378                   Sock_Start();
1379           
1380                   /* Initialize the selector */
1381                   if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
1382                   {
1383                       free(self);
1384                       return MI_RESULT_FAILED;
1385                   }
1386                   self->selector = &self->internalSelector;
1387 mike  1.1         self->internalSelectorUsed = MI_TRUE;
1388               }
1389           
1390               /* Save the callback and callbackData */
1391               self->callbackOnResponse = responseCallback;
1392               self->callbackOnStatus = statusCallback;
1393               self->callbackData = callbackData;
1394           
1395               /* Set the magic number */
1396               self->magic = _MAGIC;
1397           
1398               /* Set output parameter */
1399               *selfOut = self;
1400               return MI_RESULT_OK;
1401           }
1402           
1403           
1404           
1405           static size_t _GetHeadersSize(
1406               const HttpClientRequestHeaders* headers)
1407           {
1408 mike  1.1     size_t res = 0;
1409               size_t index = 0;
1410           
1411               while (index < headers->size)
1412               {
1413                   res += Strlen(headers->data[index]);
1414                   res += 2; /* \r \n pair */
1415                   index++;
1416               }
1417           
1418               return res;
1419           }
1420           
1421           static Page* _CreateHttpHeader(
1422               const char* verb,
1423               const char* uri,
1424               const HttpClientRequestHeaders* headers,
1425               size_t size)
1426           {
1427               Page* page = 0;
1428               size_t pageSize = 0;
1429 mike  1.1     int r;
1430               char* p;
1431           
1432           #define HTTP_HEADER_FORMAT "%s %s HTTP/1.1\r\n" \
1433               "Content-Length: %d\r\n"\
1434               "Connection: Keep-Alive\r\n" \
1435               "Host: host\r\n"
1436           
1437           #define HTTP_HEADER_FORMAT_NOCL "%s %s HTTP/1.1\r\n" \
1438               "Connection: Keep-Alive\r\n" \
1439               "Host: host\r\n"
1440           
1441               /* calculate approximate page size */
1442               if (!verb)
1443                   verb = "POST";
1444               pageSize += sizeof(HTTP_HEADER_FORMAT) + 10; /* format + 10 digits of content length */
1445               pageSize += Strlen(verb);
1446               pageSize += Strlen(uri);
1447           
1448               if (headers)
1449                   pageSize += _GetHeadersSize(headers);
1450 mike  1.1 
1451               page = (Page*)malloc(pageSize + sizeof(Page));
1452           
1453               if (!page)
1454                   return 0;
1455           
1456               /* clear header */
1457               memset(page, 0, sizeof(Page));
1458           
1459               p = (char*)(page + 1);
1460           
1461               if (size)
1462                   r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT, verb, uri, (int)size);
1463               else
1464                   r = Snprintf(p, pageSize, HTTP_HEADER_FORMAT_NOCL, verb, uri);
1465           
1466               if (r < 0)
1467               {
1468                   free(page);
1469                   return 0;
1470               }
1471 mike  1.1 
1472               p += r;
1473               pageSize -= r;
1474           
1475               if (headers)
1476               {
1477                   size_t index = 0;
1478           
1479                   while (index < headers->size)
1480                   {
1481                       r = (int)Strlcpy(p,headers->data[index], pageSize);
1482                       p += r;
1483                       pageSize -= r;
1484                       r = (int)Strlcpy(p,"\r\n", pageSize);
1485                       p += r;
1486                       pageSize -= r;
1487           
1488                       index++;
1489                   }
1490               }
1491           
1492 mike  1.1     /* add trailing \r\n */
1493               r = (int)Strlcpy(p,"\r\n", pageSize);
1494               p += r;
1495               pageSize -= r;
1496           
1497               page->u.s.size = (unsigned int)(p - (char*)(page+1));
1498           
1499               return page;
1500           }
1501           
1502           /* ************************************************************************* *\
1503                                           HTTP CLIENT
1504           \* ************************************************************************* */
1505           /*
1506               Creates new http client.
1507           
1508               Parameters:
1509               selfOut - [out] newly created http object (or null if failed).
1510               selector - [opt] selector to use for socket monitoring. If selector not specified,
1511                       private one is created.
1512               host - host address
1513 mike  1.1     port - port number
1514               secure - flag that indicates if http or https conneciton is required
1515           
1516               Returns:
1517               'OK' on success or error code otherwise
1518           */
1519           MI_Result HttpClient_New_Connector(
1520               HttpClient** selfOut,
1521               Selector* selector, /*optional, maybe NULL*/
1522               const char* host,
1523               unsigned short port,
1524               MI_Boolean secure,
1525               HttpClientCallbackOnStatus statusCallback,
1526               HttpClientCallbackOnResponse  responseCallback,
1527               void* callbackData)
1528           {
1529               HttpClient* self;
1530               MI_Result r;
1531           
1532               /* allocate this, inits selector */
1533               r = _New_Http(selfOut, selector, statusCallback, 
1534 mike  1.1         responseCallback, callbackData);
1535           
1536               if (MI_RESULT_OK != r)
1537                   return r;
1538           
1539               self = *selfOut;
1540           
1541           #ifdef CONFIG_POSIX
1542               /* Allocate ssl context */
1543               if (secure)
1544               {
1545                   /* init ssl */
1546                   SSL_library_init();
1547           
1548                   /* create context */
1549                   r = _CreateSSLContext(self);
1550           
1551                   if (r != MI_RESULT_OK)
1552                   {
1553                       HttpClient_Delete(self);
1554                       return r;
1555 mike  1.1         }
1556               }
1557           #else
1558               MI_UNUSED(secure);
1559           #endif
1560           
1561               /* Create http connector socket */
1562               {
1563                   r = _CreateConnectorSocket(self, host, port, secure);
1564           
1565                   if (r != MI_RESULT_OK)
1566                   {
1567                       HttpClient_Delete(self);
1568                       return r;
1569                   }
1570               }
1571           
1572           
1573               return MI_RESULT_OK;
1574           }
1575           
1576 mike  1.1 /*
1577               Deletes http object, disconnects form the server
1578               and frees all related resources.
1579               
1580               Parameters:
1581               self - http object
1582           
1583               Returns:
1584               OK
1585           */
1586           MI_Result HttpClient_Delete(
1587               HttpClient* self)
1588           {
1589               /* Check parameters */
1590               if (!self)
1591                   return MI_RESULT_INVALID_PARAMETER;
1592           
1593               /* Check magic number */
1594               if (self->magic != _MAGIC)
1595                   return MI_RESULT_INVALID_PARAMETER;
1596           
1597 mike  1.1     if (self->internalSelectorUsed)
1598               {
1599                   /* Release selector;
1600                   Note: selector-destory closes all sockects in a list including connector and listener */
1601                   Selector_Destroy(self->selector);
1602           
1603                   /* Shutdown the network */
1604                   Sock_Stop();
1605               }
1606               else
1607               {
1608                   /* remove connector from handler */
1609                   if (self->connector)
1610                       Selector_RemoveHandler(self->selector, &self->connector->base);
1611               }
1612           
1613               if (self->sslContext)
1614                   SSL_CTX_free(self->sslContext);
1615           
1616               /* Clear magic number */
1617               self->magic = 0xDDDDDDDD;
1618 mike  1.1 
1619               /* Free self pointer */
1620               free(self);
1621           
1622               return MI_RESULT_OK;
1623           }
1624           
1625           
1626           /* 
1627               Sends http request.
1628           
1629               Parameters:
1630               self - http object
1631               uri - request's URI
1632               headers - [opt] extra headers for request. 
1633               data - [opt] content to send. if message is accepted to be sent, 
1634                   on return *data == null (taking memory ownership)
1635           
1636               Returns:
1637               OK or appropriate error
1638            */
1639 mike  1.1 MI_Result HttpClient_StartRequest(
1640               HttpClient* self,
1641               const char* verb,
1642               const char* uri,
1643               const HttpClientRequestHeaders* headers,
1644               Page** data)
1645           {
1646           
1647               /* check params */
1648               if (!self || !uri)
1649                   return MI_RESULT_INVALID_PARAMETER;
1650           
1651               if (self->magic != _MAGIC)
1652               {
1653                   LOGW((T("start-request: invalid magic!") ));
1654                   return MI_RESULT_INVALID_PARAMETER;
1655               }
1656           
1657               if (!self->connector)
1658               {
1659                   LOGW((T("start-request: connection was closed") ));
1660 mike  1.1         return MI_RESULT_FAILED;
1661               }
1662           
1663               /* create header page */
1664               self->connector->sendHeader =
1665                   _CreateHttpHeader(verb, uri, headers, (data && *data) ? (*data)->u.s.size : 0);
1666               
1667               if (data)
1668               {
1669                   self->connector->sendPage = *data;
1670                   *data = 0;
1671               }
1672               else
1673               {
1674                   self->connector->sendPage = 0;
1675               }
1676           
1677               /* set status to failed, until we know more details */
1678               self->connector->status = MI_RESULT_FAILED;
1679               self->connector->sentSize = 0;
1680               self->connector->sendingState = RECV_STATE_HEADER;
1681 mike  1.1     self->connector->base.mask |= SELECTOR_WRITE;
1682           
1683               _RequestCallbackWrite(self->connector);
1684           
1685               return MI_RESULT_OK;
1686           }
1687           
1688           
1689           MI_Result HttpClient_Run(
1690               HttpClient* self,
1691               MI_Uint64 timeoutUsec)
1692           {
1693               /* Run the selector */
1694               return Selector_Run(self->selector, timeoutUsec);
1695           }
1696           
1697           MI_Result HttpClient_SetTimeout(
1698               HttpClient* self,
1699               MI_Uint64 timeoutUsec)
1700           {
1701               MI_Uint64 currentTimeUsec = 0;
1702 mike  1.1 
1703               Time_Now(&currentTimeUsec);
1704           
1705               /* check params */
1706               if (!self)
1707                   return MI_RESULT_INVALID_PARAMETER;
1708           
1709               if (self->magic != _MAGIC)
1710               {
1711                   LOGW((T("setTimeout: invalid magic!") ));
1712                   return MI_RESULT_INVALID_PARAMETER;
1713               }
1714           
1715               if (!self->connector)
1716                   return MI_RESULT_INVALID_PARAMETER;
1717           
1718               /* create header page */
1719               self->connector->timeoutUsec = timeoutUsec;
1720               self->connector->base.fireTimeoutAt = currentTimeUsec + self->connector->timeoutUsec;
1721           
1722               return MI_RESULT_OK;
1723 mike  1.1 }
1724           
1725           

ViewCVS 0.9.2