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

Diff for /omi/http/http.c between version 1.2 and 1.3

version 1.2, 2015/04/20 18:10:12 version 1.3, 2015/04/20 18:19:52
Line 24 
Line 24 
  
 #include <assert.h> #include <assert.h>
 #include <ctype.h> #include <ctype.h>
 #include "http.h"  #include "httpcommon.h"
 #include <sock/addr.h> #include <sock/addr.h>
 #include <sock/sock.h> #include <sock/sock.h>
 #include <sock/selector.h> #include <sock/selector.h>
 #include <base/time.h>  #include <pal/sleep.h>
 #include <base/buf.h> #include <base/buf.h>
 #include <base/log.h> #include <base/log.h>
 #include <base/result.h> #include <base/result.h>
 #include <base/strings.h>  #include <pal/strings.h>
 #include <base/io.h>  #include <pal/format.h>
 #include <base/paths.h> #include <base/paths.h>
 #include <base/base64.h>  #include <base/Strand.h>
  
 #ifdef CONFIG_POSIX #ifdef CONFIG_POSIX
 #include <openssl/ssl.h> #include <openssl/ssl.h>
Line 72 
Line 72 
  
 #endif #endif
  
 #define T MI_T  #define FORCE_TRACING 0
  
 /* #define ENABLE_TRACING  // */  //------------------------------------------------------------------------------
 #ifdef  ENABLE_TRACING  
 #define PRINTF(a)  TIMESTAMP(); printf a  
 #define TIMESTAMP() \  
 {\  
         MI_Uint64 currentTimeUsec = 0;\  
 \  
         Time_Now(&currentTimeUsec);\  
         currentTimeUsec /= 1000;    /* ms */ \  
         printf("%ds%03dms ", (int)(currentTimeUsec / 1000 % 1000), (int)(currentTimeUsec % 1000));\  
 }  
   
 #define PRINTF_2(a)  
 #else  
 #define PRINTF(a)  
 #define PRINTF_2(a)  
 #endif  
  
   #define HTTPSOCKET_STRANDAUX_NEWREQUEST 0
  
   STRAND_DEBUGNAME1( HttpSocket, NewRequest );
  
 /* /*
 **============================================================================== **==============================================================================
Line 112 
Line 98 
     MI_Uint32           magic;     MI_Uint32           magic;
     Selector        internalSelector;     Selector        internalSelector;
     Selector*       selector;     Selector*       selector;
     HttpCallbackOnNewConnection     callbackOnNewConnection;      OpenCallback    callbackOnNewConnection;
     HttpCallbackOnCloseConnection   callbackOnCloseConnection;  
     HttpCallbackOnRequest           callbackOnRequest;  
     void*                               callbackData;     void*                               callbackData;
     SSL_CTX*    sslContext;     SSL_CTX*    sslContext;
     /* options: timeouts etc */     /* options: timeouts etc */
Line 140 
Line 124 
  
 typedef struct _Http_SR_SocketData typedef struct _Http_SR_SocketData
 { {
     /* based member*/      Strand strand;
     Handler base;  
       Handler handler;    // Used on selector
   
       Http* http;
  
     /* ssl part */     /* ssl part */
     SSL* ssl;     SSL* ssl;
Line 152 
Line 139 
         (to disbale timeout) */         (to disbale timeout) */
     MI_Boolean requestIsBeingProcessed;     MI_Boolean requestIsBeingProcessed;
  
     /* link to next stack layer */  
     void* connectionData;  
   
     /* receiving data */     /* receiving data */
     char* recvBuffer;     char* recvBuffer;
     size_t recvBufferSize;     size_t recvBufferSize;
     size_t recvievedSize;      size_t receivedSize;
     Http_RecvState recvingState;     Http_RecvState recvingState;
     HttpHeaders recvHeaders;     HttpHeaders recvHeaders;
     Page* recvPage;     Page* recvPage;
       HttpRequestMsg* request;    // request msg with the request page
  
     /* sending part */     /* sending part */
     Page* sendPage;     Page* sendPage;
Line 169 
Line 154 
     Http_RecvState sendingState;     Http_RecvState sendingState;
     int httpErrorCode;     int httpErrorCode;
  
       /* pending send message */
       Message* savedSendMsg;
   
     /* Enable tracing */     /* Enable tracing */
     MI_Boolean enableTracing;     MI_Boolean enableTracing;
 } }
Line 190 
Line 178 
  
 #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8)  | (((MI_Uint16)len)) ) #define _HashCode(first,last,len) ( (((MI_Uint8)first) << 16) | (((MI_Uint8)last) << 8)  | (((MI_Uint16)len)) )
  
   _Return_type_success_(return == MI_TRUE)
 static int _Base64DecCallback(  
     const void* data,  
     size_t size,  
     void* callbackData)  
 {  
     char** str = (char**)callbackData;  
     size_t i;  
   
     for (i = 0; i < size; i++)  
     {  
         **str = ((unsigned char*)data)[i];  
         (*str)++;  
     }  
   
     return 0;  
 }  
   
 static MI_Boolean _DecodeBasicAuth(  
     HttpHeaders* recvHeaders,  
     const char * src,  
     char* tgt)  
 {  
     char* startBuffer = tgt;  
   
     /* skip spaces in value */  
   
     while (src[0] == ' ' || src[0] == '\t')  
         src++;  
   
     /* Decode the password */  
   
     if (Base64Dec(src, strlen(src), _Base64DecCallback, &tgt) != 0)  
     {  
         return MI_FALSE;  
     }  
   
     *tgt = 0;  
   
     /* decoded string has format: <uersname>[:<password>] */  
     recvHeaders->username = startBuffer;  
     startBuffer = strchr(startBuffer, ':');  
   
     if ( startBuffer )  
     {  
         *startBuffer = 0;  
         recvHeaders->password = startBuffer + 1;  
     }  
   
     return MI_TRUE;  
 }  
   
 static MI_Boolean _getNameValuePair( static MI_Boolean _getNameValuePair(
     char ** line,      _Inout_ CharPtr* line,
     char ** value,      _Out_ CharPtr* value,
     int*  nameHashCode )     int*  nameHashCode )
 { {
     int len = 0;     int len = 0;
     char* p;     char* p;
       *value = 0;
     /* find name end /hash-code */     /* find name end /hash-code */
  
       if ((*line)[0] == 0)
       {
           trace_GetNameValuePair_Failed();
           return MI_FALSE;
       }
   
     *nameHashCode =  _ToLower((MI_Uint8)(*line)[0])<<16;     *nameHashCode =  _ToLower((MI_Uint8)(*line)[0])<<16;
  
     for (len = 1; (*line)[len] != ':' && (*line)[len] != '\r'; len++ )      for (len = 1; (*line)[len] && (*line)[len] != ':' && (*line)[len] != '\r'; len++ )
         ;         ;
  
     if ((*line)[len] != ':')     if ((*line)[len] != ':')
       {
           trace_GetNameValuePair_Failed();
         return MI_FALSE;         return MI_FALSE;
       }
  
     *nameHashCode |=  (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;     *nameHashCode |=  (len) | _ToLower((MI_Uint8)(*line)[len-1])<<8;
     (*line)[len] = 0;     (*line)[len] = 0;
Line 270 
Line 217 
     *value = p;     *value = p;
  
     /* skip to end of line */     /* skip to end of line */
     for ( ; ; )      for ( ; p[0]; )
     {     {
         if (p[0] == '\r' && p[1] == '\n' &&         if (p[0] == '\r' && p[1] == '\n' &&
             (p[2] != ' ' && p[2] != '\t') )             (p[2] != ' ' && p[2] != '\t') )
Line 284 
Line 231 
  
     /* remove trailing spaces */     /* remove trailing spaces */
     p--;     p--;
   #ifdef _PREFAST_
   #pragma prefast (push)
   #pragma prefast (disable: 26001)
   #endif
       /* disabling IPv6 OACR warnings - D3M bug 56 */
     while (p[0] == ' ' || p[0] == '\t')     while (p[0] == ' ' || p[0] == '\t')
         p--;         p--;
   #ifdef _PREFAST_
   #pragma prefast (pop)
   #endif
  
     p[1] = 0;     p[1] = 0;
  
     return MI_TRUE;     return MI_TRUE;
 } }
  
 static void _ParseContentType(  
     HttpHeaders* recvHeaders,  
     char* value)  
 {  
     recvHeaders->contentType = value;  
   
     /* find attribute list */  
     while (value[0] != 0 && value[0] != ';')  
         value++;  
   
     /* Check if attribute list was provided */  
     if (value[0] == 0)  
         return;  
   
     /* terminate type/subtype; move to attributes list */  
     value[0] = 0;  
     value++;  
   
     /* skip spaces in value */  
     while (value[0] == ' ' || value[0] == '\t')  
         value++;  
   
     /* find charset attribute (if present) */  
     if (Strncasecmp(value,"charset=",8) != 0)  
         return;  
   
     value += 8;  
     recvHeaders->charset = value;  
   
     /* can be enclosed in quotes */  
     if (value[0] == '"')  
     {  
         /* skip '"' */  
         recvHeaders->charset++;  
         value++;  
         value = strchr(value, '"');  
         if (value)  
             *value = 0;  
         else  
             recvHeaders->charset = 0;  
     }  
     else  
     {  
         /*skip trialing spaces */  
         while (value[0] != 0 && value[0] != ' ' && value[0] != '\t')  
             value++;  
   
         *value = 0;  
     }  
 }  
   
 static MI_Boolean _getHeaderField( static MI_Boolean _getHeaderField(
     Http_SR_SocketData* handler,     Http_SR_SocketData* handler,
     char ** line)      _Inout_ CharPtr* line)
 { {
     char* name = *line;     char* name = *line;
     char* value = NULL;     char* value = NULL;
     int nameHashCode;     int nameHashCode;
  
     if (!_getNameValuePair(line, &value, &nameHashCode))     if (!_getNameValuePair(line, &value, &nameHashCode))
       {
           trace_GetNameValuePair_Failed();
         return MI_FALSE;         return MI_FALSE;
       }
   
  
   #if defined(CONFIG_ENABLE_HTTPHEADERS)
   
       /* Inject name-value into HTTP header array */
   
       if (handler->recvHeaders.headersSize < HTTP_MAX_HEADERS)
       {
           handler->recvHeaders.headers[handler->recvHeaders.headersSize].name =
               name;
           handler->recvHeaders.headers[handler->recvHeaders.headersSize].value =
               value;
           handler->recvHeaders.headersSize++;
       }
   
   #endif /* defined(CONFIG_ENABLE_HTTPHEADERS) */
   
       /* Convert specified headers to static fields */
  
     switch (nameHashCode)     switch (nameHashCode)
     {     {
     case (_HashCode('c','e',12)): /*Content-Type*/     case (_HashCode('c','e',12)): /*Content-Type*/
           {
         if (Strcasecmp(name,"Content-Type") == 0)         if (Strcasecmp(name,"Content-Type") == 0)
             _ParseContentType(&handler->recvHeaders, value);                  ParseContentType(&handler->recvHeaders, value);
  
         break;         break;
           }
     case (_HashCode('c','h',14)): /*Content-Length*/     case (_HashCode('c','h',14)): /*Content-Length*/
           {
         if (Strcasecmp(name,"Content-Length") == 0)         if (Strcasecmp(name,"Content-Length") == 0)
         {         {
             handler->recvHeaders.contentLength = (size_t)Strtoull(value, NULL, 10);                  handler->recvHeaders.contentLength = (size_t)Strtoull(value,
                       NULL, 10);
   
             if ( handler->recvHeaders.contentLength > HTTP_MAX_CONTENT )             if ( handler->recvHeaders.contentLength > HTTP_MAX_CONTENT )
                   {
                       trace_ContentLength_MaxCheck_Failed();
                 return MI_FALSE;                 return MI_FALSE;
         }         }
               }
         break;         break;
           }
     case (_HashCode('a','n',13)): /*Authorization*/     case (_HashCode('a','n',13)): /*Authorization*/
         if (Strcasecmp(name,"Authorization") == 0)  
         {         {
             if (Strncasecmp(value,"Basic",5) == 0)              if (Strcasecmp(name,"Authorization") == 0)
             {             {
                 /* since decoded string is smaller, performing decoding inplace;                  if( !ParseAuthorization(&handler->recvHeaders,value) )
                     for source skip 'Basic ' part (6 chars) */  
                 if (!_DecodeBasicAuth(&handler->recvHeaders, value + 6, value))  
                 {                 {
                     LOGW_CHAR(("base64 decoding error in Basic auth: [%s]\n", value));  
                     return MI_FALSE;                     return MI_FALSE;
                 }                 }
             }             }
             else    /* unknown authorization type */              break;
                 handler->recvHeaders.authorization = value;          }
           case (_HashCode('u','t',10)):
           {
               /* Remember the User-Agent for later use */
               if (Strcasecmp(name, "User-Agent") == 0)
               {
                   handler->recvHeaders.userAgent = value;
         }         }
         break;         break;
           }
     default:     default:
         break;         break;
  
Line 400 
Line 333 
  
 static MI_Boolean _getRequestLine( static MI_Boolean _getRequestLine(
     Http_SR_SocketData* handler,     Http_SR_SocketData* handler,
     char ** line)      _Inout_ CharPtr* line)
 { {
     size_t index;     size_t index;
     /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF     /* expecting  Request-Line = Method SP Request-URI SP HTTP-Version CRLF
         Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv         Read more: http://www.faqs.org/rfcs/rfc2616.html#ixzz0jKdjJdZv
     */     */
  
       if ((*line)[0] == 0)
       {
           trace_GetRequestLine_failed();
           return MI_FALSE;
       }
   
     /* skip to end of line */     /* skip to end of line */
     for ( index = 1; index < handler->recvievedSize; index++ )      for ( index = 1; (*line)[index] && index < handler->receivedSize; index++ )
     {     {
         if ((*line)[index-1] == '\r' && (*line)[index] == '\n' )         if ((*line)[index-1] == '\r' && (*line)[index] == '\n' )
         {         {
Line 417 
Line 356 
         }         }
     }     }
  
       trace_GetRequestLine_failed();
   
     return MI_FALSE;     return MI_FALSE;
 } }
  
Line 429 
Line 370 
     int res;     int res;
  
     if (!handler->ssl)     if (!handler->ssl)
         return Sock_Read(handler->base.sock, buf, buf_size, sizeRead);          return Sock_Read(handler->handler.sock, buf, buf_size, sizeRead);
  
     handler->base.mask &= ~SELECTOR_WRITE;      handler->handler.mask &= ~SELECTOR_WRITE;
     handler->base.mask |= SELECTOR_READ;      handler->handler.mask |= SELECTOR_READ;
     handler->reverseOperations = MI_FALSE;     handler->reverseOperations = MI_FALSE;
  
     *sizeRead = 0;     *sizeRead = 0;
Line 440 
Line 381 
     if (handler->acceptDone)     if (handler->acceptDone)
     {     {
         res = SSL_read(handler->ssl, buf, buf_size);         res = SSL_read(handler->ssl, buf, buf_size);
         PRINTF(("ssl read %d\n", res));  
     }     }
     else     else
     {     {
         res = SSL_accept(handler->ssl);         res = SSL_accept(handler->ssl);
         PRINTF(("ssl accept %d\n", res));  
         if ( res > 0 )         if ( res > 0 )
         {         {
             /* we are done with accpet */             /* we are done with accpet */
Line 468 
Line 408 
     {     {
     case SSL_ERROR_WANT_WRITE:     case SSL_ERROR_WANT_WRITE:
         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
         handler->base.mask |= SELECTOR_WRITE;          handler->handler.mask |= SELECTOR_WRITE;
         handler->base.mask &= ~SELECTOR_READ;          handler->handler.mask &= ~SELECTOR_READ;
         PRINTF(("ssl read/accept WANT_WRITE\n"));  
         return MI_RESULT_WOULD_BLOCK;         return MI_RESULT_WOULD_BLOCK;
  
     case SSL_ERROR_WANT_READ:     case SSL_ERROR_WANT_READ:
         PRINTF(("ssl read/accept WANT_READ\n"));  
         return MI_RESULT_WOULD_BLOCK;         return MI_RESULT_WOULD_BLOCK;
  
     case SSL_ERROR_SYSCALL:     case SSL_ERROR_SYSCALL:
Line 483 
Line 422 
             EINPROGRESS == errno)             EINPROGRESS == errno)
             return MI_RESULT_WOULD_BLOCK;             return MI_RESULT_WOULD_BLOCK;
  
         LOGW_CHAR(("ssl-read: unexpected sys error %d\n", errno));          trace_SSLRead_UnexpectedSysError(errno);
         break;         break;
  
     default:     default:
Line 495 
Line 434 
                 char err_txt[200];                 char err_txt[200];
                 ERR_error_string_n(err, err_txt, sizeof(err_txt));                 ERR_error_string_n(err, err_txt, sizeof(err_txt));
  
                 LOGW_CHAR(("ssl-read error: %d [%s]\n", (int)err, err_txt));                  trace_SSLRead_Error((int)err, scs(err_txt));
   
                 err = ERR_get_error();                 err = ERR_get_error();
             }             }
         }         }
Line 514 
Line 452 
     int res;     int res;
  
     if (!handler->ssl)     if (!handler->ssl)
         return Sock_Write(handler->base.sock, buf, buf_size, sizeWritten);          return Sock_Write(handler->handler.sock, buf, buf_size, sizeWritten);
  
     /* Do not clear READ flag, since 'close' notification     /* Do not clear READ flag, since 'close' notification
     delivered as READ event*/     delivered as READ event*/
     handler->base.mask &= ~SELECTOR_READ;      handler->handler.mask &= ~SELECTOR_READ;
     handler->base.mask |= SELECTOR_WRITE;      handler->handler.mask |= SELECTOR_WRITE;
     handler->reverseOperations = MI_FALSE;     handler->reverseOperations = MI_FALSE;
  
     *sizeWritten = 0;     *sizeWritten = 0;
     res = SSL_write(handler->ssl, buf, buf_size);     res = SSL_write(handler->ssl, buf, buf_size);
     PRINTF(("ssl write %d\n", res));  
  
     if ( res == 0 )     if ( res == 0 )
         return MI_RESULT_OK;    /* connection closed */         return MI_RESULT_OK;    /* connection closed */
Line 542 
Line 479 
  
     case SSL_ERROR_WANT_READ:     case SSL_ERROR_WANT_READ:
         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */         handler->reverseOperations = MI_TRUE;   /* wait until write is allowed */
         handler->base.mask |= SELECTOR_READ;          handler->handler.mask |= SELECTOR_READ;
         handler->base.mask &= ~SELECTOR_WRITE;          handler->handler.mask &= ~SELECTOR_WRITE;
         return MI_RESULT_WOULD_BLOCK;         return MI_RESULT_WOULD_BLOCK;
  
     case SSL_ERROR_SYSCALL:     case SSL_ERROR_SYSCALL:
Line 552 
Line 489 
             EINPROGRESS == errno)             EINPROGRESS == errno)
             return MI_RESULT_WOULD_BLOCK;             return MI_RESULT_WOULD_BLOCK;
  
         LOGW_CHAR(("ssl-write: unexpected sys error %d\n", errno));          trace_SSLWrite_UnexpectedSysError(errno);
         break;         break;
  
     default:     default:
Line 563 
Line 500 
  
 static void _WriteTraceFile(PathID id, void* data, size_t size) static void _WriteTraceFile(PathID id, void* data, size_t size)
 { {
   #ifdef CONFIG_POSIX
     static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;     static pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
   #else
       /* TODO: How to synchronize logging */
   #endif
     const char* path;     const char* path;
  
     if (!(path = GetPath(id)))      if (!(path = OMI_GetPath(id)))
         return;         return;
  
   #ifdef CONFIG_POSIX
     pthread_mutex_lock(&s_mutex);     pthread_mutex_lock(&s_mutex);
   #else
       /* TODO: How to synchronize logging */
   #endif
     {     {
         FILE* out = fopen(path, "a");         FILE* out = fopen(path, "a");
  
         if (out)         if (out)
           {
             fwrite(data, 1, size, out);             fwrite(data, 1, size, out);
   
         fclose(out);         fclose(out);
     }     }
           else
           {
               trace_CannotOpenHttptraceFile(path, errno);
           }
       }
   #ifdef CONFIG_POSIX
     pthread_mutex_unlock(&s_mutex);     pthread_mutex_unlock(&s_mutex);
   #else
       /* TODO: How to synchronize logging */
   #endif
 } }
  
 INLINE MI_Result _Sock_Read( INLINE MI_Result _Sock_Read(
Line 589 
Line 543 
 { {
     MI_Result r = _Sock_ReadAux(handler, buf, buf_size, sizeRead);     MI_Result r = _Sock_ReadAux(handler, buf, buf_size, sizeRead);
  
     if (r == MI_RESULT_OK && handler->enableTracing)      if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
     {     {
         _WriteTraceFile(ID_HTTPRECVTRACEFILE, buf, *sizeRead);         _WriteTraceFile(ID_HTTPRECVTRACEFILE, buf, *sizeRead);
     }     }
Line 605 
Line 559 
 { {
     MI_Result r = _Sock_WriteAux(handler, buf, buf_size, sizeWritten);     MI_Result r = _Sock_WriteAux(handler, buf, buf_size, sizeWritten);
  
     if (r == MI_RESULT_OK && handler->enableTracing)      if (FORCE_TRACING || (r == MI_RESULT_OK && handler->enableTracing))
     {     {
         _WriteTraceFile(ID_HTTPSENDTRACEFILE, buf, *sizeWritten);         _WriteTraceFile(ID_HTTPSENDTRACEFILE, buf, *sizeWritten);
     }     }
Line 627 
Line 581 
     if (handler->recvingState == RECV_STATE_CONTENT)     if (handler->recvingState == RECV_STATE_CONTENT)
         return PRT_CONTINUE;         return PRT_CONTINUE;
  
     buf = handler->recvBuffer + handler->recvievedSize;      buf = handler->recvBuffer + handler->receivedSize;
     buf_size = handler->recvBufferSize - handler->recvievedSize;      buf_size = handler->recvBufferSize - handler->receivedSize;
     received = 0;     received = 0;
  
     r = _Sock_Read(handler, buf, buf_size, &received);     r = _Sock_Read(handler, buf, buf_size, &received);
     PRINTF(("%d: read r = %d, recv = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)received, (int)handler->reverseOperations ));  
  
     if ( r == MI_RESULT_OK && 0 == received )     if ( r == MI_RESULT_OK && 0 == received )
         return PRT_RETURN_FALSE; /* conection closed */         return PRT_RETURN_FALSE; /* conection closed */
Line 643 
Line 596 
     if (!received)     if (!received)
         return PRT_RETURN_TRUE;         return PRT_RETURN_TRUE;
  
     handler->recvievedSize += received;      handler->receivedSize += received;
   
     /* check header */  
     PRINTF_2(("%s\n",buf));  
  
     /* did we get full header? */     /* did we get full header? */
     buf = handler->recvBuffer;     buf = handler->recvBuffer;
     for ( index = 3; index < handler->recvievedSize; index++ )      for ( index = 3; index < handler->receivedSize; index++ )
     {     {
         if (buf[index-3] == '\r' && buf[index-1] == '\r' &&         if (buf[index-3] == '\r' && buf[index-1] == '\r' &&
             buf[index-2] == '\n' && buf[index] == '\n' )             buf[index-2] == '\n' && buf[index] == '\n' )
Line 662 
Line 612 
  
     if (!fullHeaderReceived )     if (!fullHeaderReceived )
     {     {
         if ( handler->recvievedSize <  handler->recvBufferSize )          if ( handler->receivedSize <  handler->recvBufferSize )
             return PRT_RETURN_TRUE; /* continue reading */             return PRT_RETURN_TRUE; /* continue reading */
  
         if ( handler->recvBufferSize < MAX_HEADER_SIZE )         if ( handler->recvBufferSize < MAX_HEADER_SIZE )
         {         {
             buf = realloc(handler->recvBuffer, handler->recvBufferSize * 2);              buf = PAL_Realloc(handler->recvBuffer, handler->recvBufferSize * 2);
  
             if (!buf)             if (!buf)
                 return PRT_RETURN_FALSE;                 return PRT_RETURN_FALSE;
Line 679 
Line 629 
         else         else
         {         {
             /* http header is too big - drop connection */             /* http header is too big - drop connection */
             LOGW((T("http header is too big; dropping connection\n")));              trace_HttpHeaderIsTooBig();
             return PRT_RETURN_FALSE;             return PRT_RETURN_FALSE;
         }         }
     }     }
Line 700 
Line 650 
     }     }
  
     /* Allocate zero-terminated buffer */     /* Allocate zero-terminated buffer */
     handler->recvPage = (Page*)malloc(sizeof(Page) + handler->recvHeaders.contentLength + 1);      handler->recvPage = (Page*)PAL_Malloc(sizeof(Page) + handler->recvHeaders.contentLength + 1);
  
     if (!handler->recvPage)     if (!handler->recvPage)
         return PRT_RETURN_FALSE;         return PRT_RETURN_FALSE;
Line 710 
Line 660 
     handler->recvPage->u.s.size = (unsigned int)handler->recvHeaders.contentLength;     handler->recvPage->u.s.size = (unsigned int)handler->recvHeaders.contentLength;
     handler->recvPage->u.s.next = 0;     handler->recvPage->u.s.next = 0;
  
     handler->recvievedSize -= index + 1;      handler->receivedSize -= index + 1;
  
     /* Verify that we have not more than 'content-length' bytes in buffer left     /* Verify that we have not more than 'content-length' bytes in buffer left
         If we hvae more, assuming http client is invalid and drop connection */         If we hvae more, assuming http client is invalid and drop connection */
     if (handler->recvievedSize > handler->recvHeaders.contentLength)      if (handler->receivedSize > handler->recvHeaders.contentLength)
     {     {
         LOGW((T("http payload is bigger than content-length\n")));          trace_HttpPayloadIsBiggerThanContentLength();
         return PRT_RETURN_FALSE;         return PRT_RETURN_FALSE;
     }     }
  
     memcpy( handler->recvPage + 1, data, handler->recvievedSize );      memcpy( handler->recvPage + 1, data, handler->receivedSize );
     handler->recvingState = RECV_STATE_CONTENT;     handler->recvingState = RECV_STATE_CONTENT;
  
     PRINTF_2(("full header read; page size %d, position %d\n", handler->recvPage->u.s.size, handler->recvievedSize));  
   
     return PRT_CONTINUE;     return PRT_CONTINUE;
 } }
  
 static Http_CallbackResult _ReadData( static Http_CallbackResult _ReadData(
     Http_SR_SocketData* handler)     Http_SR_SocketData* handler)
 { {
     Http* self = (Http*)handler->base.data;  
     char* buf;     char* buf;
     size_t buf_size, received;     size_t buf_size, received;
     MI_Result r;     MI_Result r;
       HttpRequestMsg* msg;
  
     /* are we in the right state? */     /* are we in the right state? */
     if (handler->recvingState != RECV_STATE_CONTENT)     if (handler->recvingState != RECV_STATE_CONTENT)
         return PRT_RETURN_FALSE;         return PRT_RETURN_FALSE;
  
     buf = ((char*)(handler->recvPage + 1)) + handler->recvievedSize;      buf = ((char*)(handler->recvPage + 1)) + handler->receivedSize;
     buf_size = handler->recvHeaders.contentLength - handler->recvievedSize;      buf_size = handler->recvHeaders.contentLength - handler->receivedSize;
     received = 0;     received = 0;
  
     if (buf_size)     if (buf_size)
     {     {
         r = _Sock_Read(handler, buf, buf_size, &received);         r = _Sock_Read(handler, buf, buf_size, &received);
  
         PRINTF(("%d: read r = %d, recv = %d\n", (int)handler->base.sock, (int)r, (int)received ));  
   
         if ( r == MI_RESULT_OK && 0 == received )         if ( r == MI_RESULT_OK && 0 == received )
             return PRT_RETURN_FALSE; /* conection closed */             return PRT_RETURN_FALSE; /* conection closed */
  
         if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )         if ( r != MI_RESULT_OK && r != MI_RESULT_WOULD_BLOCK )
             return PRT_RETURN_FALSE;             return PRT_RETURN_FALSE;
  
         handler->recvievedSize += received;          handler->receivedSize += received;
     }     }
  
     /* did we get all data? */     /* did we get all data? */
     PRINTF_2(("dt status - %d / %d\n", (int)handler->recvievedSize, (int)handler->recvHeaders.contentLength));  
  
     if ( handler->recvievedSize != handler->recvHeaders.contentLength )      if ( handler->receivedSize != handler->recvHeaders.contentLength )
         return PRT_RETURN_TRUE;         return PRT_RETURN_TRUE;
  
     handler->requestIsBeingProcessed = MI_TRUE;      msg = HttpRequestMsg_New(handler->recvPage, &handler->recvHeaders);
     (*self->callbackOnRequest)( self, self->callbackData, handler->connectionData, handler, &handler->recvHeaders,  
         &handler->recvPage );      if( NULL == msg )
       {
           trace_HTTP_RequestAllocFailed( handler );
  
     if (handler->recvPage)     if (handler->recvPage)
         free(handler->recvPage);          {
               PAL_Free(handler->recvPage);
               handler->recvPage = NULL; /* clearing this out so that caller does not double-free it */
           }
   
           return PRT_RETURN_FALSE;
       }
   
       handler->requestIsBeingProcessed = MI_TRUE;
   
       // the page will be owned by receiver of this message
       DEBUG_ASSERT( NULL == handler->request );
       handler->request = msg;
       Strand_ScheduleAux( &handler->strand, HTTPSOCKET_STRANDAUX_NEWREQUEST );
  
     handler->recvPage = 0;     handler->recvPage = 0;
     handler->recvievedSize = 0;      handler->receivedSize = 0;
     memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));     memset(&handler->recvHeaders, 0, sizeof(handler->recvHeaders));
     handler->recvingState = RECV_STATE_HEADER;     handler->recvingState = RECV_STATE_HEADER;
     return PRT_CONTINUE;     return PRT_CONTINUE;
Line 820 
Line 780 
     return "Error";     return "Error";
 } }
  
   /*
    * Common clean up function that reverts the changes made when preparing
    * the strand for a write.
    */
   static void _ResetWriteState(
       Http_SR_SocketData* socketData )
   {
       if (socketData->sendPage)
       {
           PAL_Free(socketData->sendPage);
           socketData->sendPage = 0;
       }
       socketData->httpErrorCode = 0;
       socketData->sentSize = 0;
       socketData->sendingState = RECV_STATE_HEADER;
       socketData->handler.mask &= ~SELECTOR_WRITE;
       socketData->handler.mask |= SELECTOR_READ;
   }
   
 static Http_CallbackResult _WriteHeader( static Http_CallbackResult _WriteHeader(
     Http_SR_SocketData* handler)     Http_SR_SocketData* handler)
 { {
Line 830 
Line 809 
     "Content-Type: application/soap+xml;charset=UTF-8\r\n"\     "Content-Type: application/soap+xml;charset=UTF-8\r\n"\
     "\r\n"     "\r\n"
  
   #define RESPONSE_HEADER_NO_AUTH_FMT "HTTP/1.1 %d %s\r\n\r\n"
   
   #define RESPONSE_HEADER_401_ERROR_FMT \
       "HTTP/1.1 %d %s \r\n" \
       HTTP_WWWAUTHENTICATE_BASIC\
       "\r\n"\
       "Content-Length: 0\r\n"\
       "\r\n"
   
 /*    "SOAPAction: http://schemas.xmlsoap.org/ws/2004/08/addressing/fault\r\n"\ */ /*    "SOAPAction: http://schemas.xmlsoap.org/ws/2004/08/addressing/fault\r\n"\ */
  
     char currentLine[sizeof(RESPONSE_HEADER_FMT) +     char currentLine[sizeof(RESPONSE_HEADER_FMT) +
Line 860 
Line 848 
     }     }
     else     else
     {     {
           int httpErrorCode = (int)handler->httpErrorCode;
           /*
           Check the error code and in case it is "HTTP_ERROR_CODE_UNAUTHORIZED" (401), then we need to send the
           "WWW-Authenticate" header field. Since right now we only support "Basic" auth so the header will contains
           "WWW-Authenticate: Basic realm=\"WSMAN\".
           */
           char * response =  (httpErrorCode == HTTP_ERROR_CODE_UNAUTHORIZED) ? RESPONSE_HEADER_401_ERROR_FMT : RESPONSE_HEADER_NO_AUTH_FMT;
   
         buf_size = (size_t)Snprintf(         buf_size = (size_t)Snprintf(
             currentLine,             currentLine,
             sizeof(currentLine),             sizeof(currentLine),
             "HTTP/1.1 %d %s\r\n\r\n",              response,
             (int)handler->httpErrorCode,              httpErrorCode,
             _GetHttpErrorCodeDescription(handler->httpErrorCode));             _GetHttpErrorCodeDescription(handler->httpErrorCode));
     }     }
  
Line 874 
Line 870 
  
     r = _Sock_Write(handler, buf, buf_size - handler->sentSize, &sent);     r = _Sock_Write(handler, buf, buf_size - handler->sentSize, &sent);
  
     PRINTF(("%d: write r = %d, sent = %d; reverse %d\n", (int)handler->base.sock, (int)r, (int)sent, (int)handler->reverseOperations ));  
   
     if ( r == MI_RESULT_OK && 0 == sent )     if ( r == MI_RESULT_OK && 0 == sent )
         return PRT_RETURN_FALSE; /* conection closed */         return PRT_RETURN_FALSE; /* conection closed */
  
Line 908 
Line 902 
  
     if (!handler->sendPage)     if (!handler->sendPage)
     {   /* no content*/     {   /* no content*/
         handler->httpErrorCode = 0;          _ResetWriteState( handler );
         handler->sentSize = 0;  
         handler->sendingState = RECV_STATE_HEADER;  
         handler->base.mask &= ~SELECTOR_WRITE;  
         handler->base.mask |= SELECTOR_READ;  
         return PRT_CONTINUE;         return PRT_CONTINUE;
     }     }
  
Line 922 
Line 912 
  
     r = _Sock_Write(handler, buf, buf_size, &sent);     r = _Sock_Write(handler, buf, buf_size, &sent);
  
     PRINTF(("%d: write r = %d, sent = %d\n", (int)handler->base.sock, (int)r, (int)sent ));  
   
     if ( r == MI_RESULT_OK && 0 == sent )     if ( r == MI_RESULT_OK && 0 == sent )
         return PRT_RETURN_FALSE; /* conection closed */         return PRT_RETURN_FALSE; /* conection closed */
  
Line 937 
Line 925 
     if ( handler->sentSize != handler->sendPage->u.s.size )     if ( handler->sentSize != handler->sendPage->u.s.size )
         return PRT_RETURN_TRUE;         return PRT_RETURN_TRUE;
  
     free(handler->sendPage);      _ResetWriteState( handler );
     handler->sendPage = 0;  
     handler->httpErrorCode = 0;  
     handler->sentSize = 0;  
     handler->sendingState = RECV_STATE_HEADER;  
     handler->base.mask &= ~SELECTOR_WRITE;  
     handler->base.mask |= SELECTOR_READ;  
  
     return PRT_CONTINUE;     return PRT_CONTINUE;
 } }
Line 955 
Line 937 
     {     {
     case PRT_CONTINUE: break;     case PRT_CONTINUE: break;
     case PRT_RETURN_TRUE: return MI_TRUE;     case PRT_RETURN_TRUE: return MI_TRUE;
     case PRT_RETURN_FALSE: return MI_FALSE;      case PRT_RETURN_FALSE:
           _ResetWriteState( handler );
           return MI_FALSE;
     }     }
  
     switch (_WriteData(handler))     switch (_WriteData(handler))
     {     {
     case PRT_CONTINUE: break;     case PRT_CONTINUE: break;
     case PRT_RETURN_TRUE: return MI_TRUE;     case PRT_RETURN_TRUE: return MI_TRUE;
     case PRT_RETURN_FALSE: return MI_FALSE;      case PRT_RETURN_FALSE:
           _ResetWriteState( handler );
           return MI_FALSE;
     }     }
     return MI_TRUE;     return MI_TRUE;
 } }
Line 973 
Line 959 
     MI_Uint32 mask,     MI_Uint32 mask,
     MI_Uint64 currentTimeUsec)     MI_Uint64 currentTimeUsec)
 { {
     Http_SR_SocketData* handler = (Http_SR_SocketData*)handlerIn;      Http_SR_SocketData* handler = FromOffset( Http_SR_SocketData, handler, handlerIn );
     sel=sel;     sel=sel;
  
     if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||     if ( ((mask & SELECTOR_READ) != 0 && !handler->reverseOperations) ||
         ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )         ((mask & SELECTOR_WRITE) != 0 && handler->reverseOperations) )
     {     {
         if (!_RequestCallbackRead(handler))         if (!_RequestCallbackRead(handler))
           {
               trace_RequestCallbackRead_Failed(handler);
             return MI_FALSE;             return MI_FALSE;
     }     }
       }
  
     if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||     if ( ((mask & SELECTOR_WRITE) != 0 && !handler->reverseOperations) ||
         ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )         ((mask & SELECTOR_READ) != 0 && handler->reverseOperations) )
     {     {
         if (!_RequestCallbackWrite(handler))         if (!_RequestCallbackWrite(handler))
           {
               trace_RequestCallbackWrite_Failed();
             return MI_FALSE;             return MI_FALSE;
     }     }
       }
  
     /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */     /* re-set timeout - if we performed R/W operation, set timeout depending where we are in communication */
     if (mask & (SELECTOR_READ | SELECTOR_WRITE))     if (mask & (SELECTOR_READ | SELECTOR_WRITE))
     {     {
         Http* self = (Http*)handler->base.data;          Http* self = (Http*)handler->handler.data;
  
         if (handler->requestIsBeingProcessed)         if (handler->requestIsBeingProcessed)
         {         {
             /* since request is processed by server, disable timeout for this period */             /* since request is processed by server, disable timeout for this period */
             handler->base.fireTimeoutAt = TIME_NEVER;              handler->handler.fireTimeoutAt = TIME_NEVER;
         }         }
         else         else
         {         {
             /* Use configuration timeout */             /* Use configuration timeout */
             handler->base.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;              handler->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
         }         }
     }     }
  
     /* Close conenction by timeout */     /* Close conenction by timeout */
     if (mask & SELECTOR_TIMEOUT)     if (mask & SELECTOR_TIMEOUT)
       {
           trace_ConnectionClosed_Timeout();
         return MI_FALSE;         return MI_FALSE;
       }
  
     if ((mask & SELECTOR_REMOVE) != 0 ||     if ((mask & SELECTOR_REMOVE) != 0 ||
         (mask & SELECTOR_DESTROY) != 0)         (mask & SELECTOR_DESTROY) != 0)
     {     {
         Http* self = (Http*)handler->base.data;  
   
         /* notify next stack layer */  
         (*self->callbackOnCloseConnection)(  
             self,  
             self->callbackData,  
             handler->connectionData );  
   
         if (handler->ssl)         if (handler->ssl)
             SSL_free(handler->ssl);             SSL_free(handler->ssl);
  
         PRINTF(("%d: close\n", (int)handler->base.sock));          trace_SocketClose_REMOVEDESTROY();
  
         Sock_Close(handler->base.sock);          Sock_Close(handler->handler.sock);
   
           // Free the savedSendMsg and ACK it to prevent leaks when a non-io thread
           // writes to the socket, but it cannot be read because of an error or a
           // ECONNRESET.
           if (handler->savedSendMsg)
           {
               Message_Release(handler->savedSendMsg);
               handler->savedSendMsg = NULL;
               DEBUG_ASSERT(handler->strand.info.otherAckPending);
               Strand_ScheduleAck( &handler->strand );
           }
  
         if (handler->recvPage)         if (handler->recvPage)
             free(handler->recvPage);              PAL_Free(handler->recvPage);
  
         if (handler->sendPage)         if (handler->sendPage)
             free(handler->sendPage);              PAL_Free(handler->sendPage);
   
           PAL_Free(handler->recvBuffer);
           // handler deleted on its own strand
  
         free(handler->recvBuffer);          // notify next stack layer
         free(handler);          // (only after internal data has been deleted as this may delete the object)
           Strand_ScheduleClose( &handler->strand );
     }     }
  
     return MI_TRUE;     return MI_TRUE;
 } }
  
   /*
   **==============================================================================
   */
   
   static void _SendIN_IO_thread_HttpSocket(void* self_, Message* message)
   {
       Http_SR_SocketData* sendSock = (Http_SR_SocketData*)self_;
       HttpResponseMsg * response = (HttpResponseMsg *)message;
   
       DEBUG_ASSERT( sendSock );
       DEBUG_ASSERT( HttpResponseMsgTag == message->tag );
   
       /* validate handler */
   
       if (MI_RESULT_OK != Selector_ContainsHandler(
               sendSock->http->selector, &sendSock->handler ) )
       {
           trace_SendIN_IO_thread_HttpSocket_InvalidHandler(sendSock);
           return;
       }
   
       sendSock->requestIsBeingProcessed = MI_FALSE;
   
       sendSock->handler.mask |= SELECTOR_WRITE;
       sendSock->handler.mask &= ~SELECTOR_READ;
   
       // Now we take ownership of the page
       sendSock->sendPage = response->page;
       response->page = NULL;
       sendSock->httpErrorCode = response->httpErrorCode;
   
       sendSock->sentSize = 0;
       sendSock->sendingState = RECV_STATE_HEADER;
   
       // Done after response->page is NULL'd to prevent early release
       // of that memory in the message's destructor
       DEBUG_ASSERT( sendSock->savedSendMsg );
       Message_Release(sendSock->savedSendMsg);
       sendSock->savedSendMsg = NULL;
   
       if( !_RequestCallbackWrite(sendSock) )
       {
           trace_SendIN_IO_thread_HttpSocket_WriteFailed();
       }
   
       Strand_ScheduleAck( &sendSock->strand );
   }
   
   void _HttpSocket_Post( _In_ Strand* self_, _In_ Message* msg)
   {
       Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
       DEBUG_ASSERT( NULL != self_ );
       trace_HttpSocketPosting(&self->strand.info.interaction, self->strand.info.interaction.other);
   
       // Preserve the message in case there is an error while writing it to the socket during
       // non-IO thread calls to Selector_CallInIOThread.
       // A ref to the message is held until the message is ACK'd.
       DEBUG_ASSERT( NULL == self->savedSendMsg );
       Message_AddRef(msg);
       self->savedSendMsg = msg;
   
       if( MI_RESULT_OK != Selector_CallInIOThread(
           self->http->selector, _SendIN_IO_thread_HttpSocket, self, msg ) )
       {
           // We also need to release the page (if any)
           HttpResponseMsg * response = (HttpResponseMsg *)msg;
           DEBUG_ASSERT( HttpResponseMsgTag == msg->tag );
   
           trace_HttpSocket_CannotPostMessage( self, msg, &self->strand.info.interaction, self->strand.info.interaction.other );
   
           HttpResponseMsg_Release( response );  // same message as savedSendMsg
           self->savedSendMsg = NULL;
           Strand_ScheduleAck( &self->strand );
       }
   }
   
   void _HttpSocket_PostControl( _In_ Strand* self, _In_ Message* msg)
   {
       DEBUG_ASSERT( MI_FALSE );  // not used yet
   }
   
   void _HttpSocket_Ack( _In_ Strand* self)
   {
       trace_HttpSocketAck( &self->info.interaction, self->info.interaction.other );
       // No need to do anything for now
   }
   
   void _HttpSocket_Cancel( _In_ Strand* self)
   {
       // no need to do anything here (upper layer should send proper error response)
   }
   
   void _HttpSocket_Finish( _In_ Strand* self_)
   {
       Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
       DEBUG_ASSERT( NULL != self_ );
   
       trace_HttpSocketFinish( self_ );
       Strand_Delete( &self->strand );
   }
   
   // HTTPSOCKET_STRANDAUX_NEWREQUEST
   void _HttpSocket_Aux_NewRequest( _In_ Strand* self_)
   {
       Http_SR_SocketData* self = (Http_SR_SocketData*)self_;
       HttpRequestMsg* msg;
   
       DEBUG_ASSERT( NULL != self_ );
       msg = self->request;
       DEBUG_ASSERT( NULL != msg );
   
       trace_HttpSocketAuxNewRequest( self, msg );
       self->request = NULL;
   
       if( !self_->info.thisClosedOther )
       {
           // Leave the strand for the case where the new request provider
           // is in-proc and takes over the thread
           Strand_PostAndLeaveStrand( &self->strand, &msg->base );
       }
   
       HttpRequestMsg_Release( msg );
   }
   
   /*
       Object that implements the HTTP protocol endpoint on a TCP Socket.
       Usually connects to WSMAN interaction object.
   
       Behaviour:
       - Post tries to schedule the operation on the IO thread (thru selector)
          if that fails it sends the Ack immediately. Note that the response message
          is delivered from WSMAN inside a HttpResponseMsg
       - Post control is not implemented
       - Both Cancel, Close and Ack do nothing (in case of cancelation upper layer should
          send an actual response)
       - Shutdown:
          Once the connection is closed by the client that is notified to _RequestCallback
          which calls Strand_ScheduleClose on component to the right.
          From there normal Strand logic applies: once the upper layer
          also closes the interaction the object is deleted.
   
       Unique features and special Behavour:
       - When a complete message has been read instead of scheduling a post
          the auxiliary function HTTPSOCKET_STRANDAUX_NEWREQUEST is
          scheduled instead. That function takes care of posting using
          Strand_PostAndLeaveStrand (which avoids holding the strand in case the thread
          is going to be hijacked  by the provider in the processing of that post).
   */
   static StrandFT _HttpSocket_FT = {
       _HttpSocket_Post,
       _HttpSocket_PostControl,
       _HttpSocket_Ack,
       _HttpSocket_Cancel,
       NULL,
       _HttpSocket_Finish,
       NULL,
       _HttpSocket_Aux_NewRequest,
       NULL,
       NULL,
       NULL,
       NULL };
   
   /*
   **==============================================================================
   */
   
 static MI_Boolean _ListenerCallback( static MI_Boolean _ListenerCallback(
     Selector* sel,     Selector* sel,
     Handler* handler_,     Handler* handler_,
Line 1068 
Line 1236 
             /* Accept the incoming connection */             /* Accept the incoming connection */
             r = Sock_Accept(handler->base.sock, &s, &addr);             r = Sock_Accept(handler->base.sock, &s, &addr);
  
             PRINTF(("%d: accept r = %d\n", (int)s, (int)r ));  
   
             if (MI_RESULT_WOULD_BLOCK == r)             if (MI_RESULT_WOULD_BLOCK == r)
                 return MI_TRUE;                 return MI_TRUE;
  
  
             if (r != MI_RESULT_OK)             if (r != MI_RESULT_OK)
             {             {
                 LOGW((T("Sock_Accept() failed; err %d\n"), Sock_GetLastError()));                  trace_SockAccept_Failed(Sock_GetLastError());
                 return MI_TRUE;                 return MI_TRUE;
             }             }
  
             r = Sock_SetBlocking(s, MI_FALSE);             r = Sock_SetBlocking(s, MI_FALSE);
             if (r != MI_RESULT_OK)             if (r != MI_RESULT_OK)
             {             {
                 LOGW((T("Sock_SetBlocking() failed\n")));                  trace_SockSetBlocking_Failed();
                 Sock_Close(s);                 Sock_Close(s);
                 return MI_TRUE;                 return MI_TRUE;
             }             }
  
             /* Create handler */             /* Create handler */
             h = (Http_SR_SocketData*)calloc(1, sizeof(Http_SR_SocketData));              h = (Http_SR_SocketData*)Strand_New( STRAND_DEBUG( HttpSocket ) &_HttpSocket_FT, sizeof(Http_SR_SocketData), STRAND_FLAG_ENTERSTRAND, NULL );
  
             if (!h)             if (!h)
             {             {
                   trace_SocketClose_Http_SR_SocketDataAllocFailed();
                 Sock_Close(s);                 Sock_Close(s);
                 return MI_TRUE;                 return MI_TRUE;
             }             }
  
               h->http = self;
             h->recvBufferSize = INITIAL_BUFFER_SIZE;             h->recvBufferSize = INITIAL_BUFFER_SIZE;
             h->recvBuffer = (char*)calloc(1, h->recvBufferSize);              h->recvBuffer = (char*)PAL_Calloc(1, h->recvBufferSize);
             if (!h->recvBuffer)             if (!h->recvBuffer)
             {             {
                 free(h);                  Strand_Delete(&h->strand);
                   trace_SocketClose_recvBuffer_AllocFailed();
                 Sock_Close(s);                 Sock_Close(s);
                 return MI_TRUE;                 return MI_TRUE;
             }             }
  
             h->base.sock = s;              h->handler.sock = s;
             h->base.mask = SELECTOR_READ | SELECTOR_EXCEPTION;              h->handler.mask = SELECTOR_READ | SELECTOR_EXCEPTION;
             h->base.callback = _RequestCallback;              h->handler.callback = _RequestCallback;
             h->base.data = self;              h->handler.data = self;
             h->base.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;              h->handler.fireTimeoutAt = currentTimeUsec + self->options.timeoutUsec;
             h->enableTracing = self->options.enableTracing;             h->enableTracing = self->options.enableTracing;
  
             /* ssl support */             /* ssl support */
Line 1120 
Line 1289 
  
                 if (!h->ssl)                 if (!h->ssl)
                 {                 {
                     LOGW((T("ssl_new() failed\n")));                      trace_SSLNew_Failed();
                     free(h);                      Strand_Delete(&h->strand);
                     Sock_Close(s);                     Sock_Close(s);
                     return MI_TRUE;                     return MI_TRUE;
                 }                 }
  
                 if (!(SSL_set_fd(h->ssl, s) ))                 if (!(SSL_set_fd(h->ssl, s) ))
                 {                 {
                     LOGW((T("ssl_set_fd() failed\n")));                      trace_SSL_setfd_Failed();
                     SSL_free(h->ssl);                     SSL_free(h->ssl);
                     free(h);                      Strand_Delete(&h->strand);
                     Sock_Close(s);                     Sock_Close(s);
                     return MI_TRUE;                     return MI_TRUE;
                 }                 }
Line 1138 
Line 1307 
             }             }
  
             /* Watch for read events on the incoming connection */             /* Watch for read events on the incoming connection */
             r = Selector_AddHandler(self->selector, &h->base);              r = Selector_AddHandler(self->selector, &h->handler);
  
             if (r != MI_RESULT_OK)             if (r != MI_RESULT_OK)
             {             {
                 LOGW((T("Selector_AddHandler() failed\n")));                  trace_SelectorAddHandler_Failed();
                 if (handler->secure)                 if (handler->secure)
                     SSL_free(h->ssl);                     SSL_free(h->ssl);
                 free(h);                  Strand_Delete(&h->strand);
                 Sock_Close(s);                 Sock_Close(s);
                 return MI_TRUE;                 return MI_TRUE;
             }             }
  
             /* notify next stack layer about new connection */              // notify next stack layer about new connection
             (*self->callbackOnNewConnection)(              // (open the interaction)
                 self,              Strand_Open(
                   &h->strand,
                   self->callbackOnNewConnection,
                 self->callbackData,                 self->callbackData,
                 h,                  NULL,
                 &h->connectionData );                  MI_TRUE );
         }         }
     }     }
  
     if ((mask & SELECTOR_REMOVE) != 0 ||     if ((mask & SELECTOR_REMOVE) != 0 ||
         (mask & SELECTOR_DESTROY) != 0)         (mask & SELECTOR_DESTROY) != 0)
     {     {
           trace_SocketClose_REMOVEDESTROY();
         Sock_Close(handler->base.sock);         Sock_Close(handler->base.sock);
         free(handler);          PAL_Free(handler);
     }     }
  
     return MI_TRUE;     return MI_TRUE;
 } }
  
 static MI_Result _New_Http( static MI_Result _New_Http(
     Http** selfOut,      _Out_       Http**              selfOut,
     Selector* selector, /*optional, maybe NULL*/      _In_        Selector*           selector, /*optional, maybe NULL*/
     HttpCallbackOnNewConnection callbackOnNewConnection,      _In_        OpenCallback        callbackOnNewConnection,
     HttpCallbackOnCloseConnection callbackOnCloseConnection,      _In_opt_    void*               callbackData)
     HttpCallbackOnRequest callbackOnRequest,  
     void* callbackData)  
 { {
     Http* self;     Http* self;
  
Line 1188 
Line 1358 
  
     /* Allocate structure */     /* Allocate structure */
     {     {
         self = (Http*)calloc(1, sizeof(Http));          self = (Http*)PAL_Calloc(1, sizeof(Http));
  
         if (!self)         if (!self)
             return MI_RESULT_FAILED;             return MI_RESULT_FAILED;
Line 1207 
Line 1377 
         /* Initialize the selector */         /* Initialize the selector */
         if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)         if (Selector_Init(&self->internalSelector) != MI_RESULT_OK)
         {         {
             free(self);              PAL_Free(self);
             return MI_RESULT_FAILED;             return MI_RESULT_FAILED;
         }         }
         self->selector = &self->internalSelector;         self->selector = &self->internalSelector;
Line 1215 
Line 1385 
     }     }
  
     /* Save the callback and callbackData */     /* Save the callback and callbackData */
     self->callbackOnRequest = callbackOnRequest;  
     self->callbackOnCloseConnection = callbackOnCloseConnection;  
     self->callbackOnNewConnection = callbackOnNewConnection;     self->callbackOnNewConnection = callbackOnNewConnection;
     self->callbackData = callbackData;     self->callbackData = callbackData;
  
     /* Set the magic number */     /* Set the magic number */
     self->magic = _MAGIC;     self->magic = _MAGIC;
  
     /* options */  
     {  
         HttpOptions options = DEFAULT_HTTP_OPTIONS;  
         self->options = options;  
     }  
   
     /* Set output parameter */     /* Set output parameter */
     *selfOut = self;     *selfOut = self;
     return MI_RESULT_OK;     return MI_RESULT_OK;
Line 1245 
Line 1407 
  
     if (!is)     if (!is)
     {     {
         LOGE_CHAR((          trace_SSL_FailedToOpenPrivateKeyFile(scs(keyPath));
             "---> SSL: failed to open private key file: %s",  
             keyPath));  
         return MI_FALSE;         return MI_FALSE;
     }     }
  
Line 1258 
Line 1418 
  
     if (!pkey)     if (!pkey)
     {     {
         LOGE_CHAR(("---> SSL: failed to create private key"));          trace_SSL_FailedToCreatePrivateKey();
         return MI_FALSE;         return MI_FALSE;
     }     }
  
Line 1271 
Line 1431 
     if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)     if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
     {     {
         EVP_PKEY_free(pkey);         EVP_PKEY_free(pkey);
         LOGE_CHAR((          trace_SSL_NoPrivateKeyFound(scs(keyPath));
             "---> SSL: no private key found in %s",  
             keyPath));  
         return MI_FALSE;         return MI_FALSE;
     }     }
  
Line 1283 
Line 1441 
  
     if (!SSL_CTX_check_private_key(ctx))     if (!SSL_CTX_check_private_key(ctx))
     {     {
         LOGE_CHAR((          trace_SSL_PrivateAndPublicKeyDonotMatch();
             "---> SSL: Private and public key do not match"));  
         return MI_FALSE;         return MI_FALSE;
     }     }
  
     return MI_TRUE;     return MI_TRUE;
 } }
  
 static MI_Result _CreateSSLContext(Http* self)  static MI_Result _CreateSSLContext(Http* self, const char* sslCipherSuite, Server_SSL_Options sslOptions)
 { {
     SSL_CTX * sslContext = 0;     SSL_CTX * sslContext = 0;
       long options = 0;
  
     sslContext = SSL_CTX_new(SSLv23_method());     sslContext = SSL_CTX_new(SSLv23_method());
  
     if (!sslContext)     if (!sslContext)
     {     {
         LOGE_CHAR((          trace_SSL_CannotCreateContext();
             "---> SSL: cannot create ssl context"));          return MI_RESULT_FAILED;
       }
   
       if (sslCipherSuite != NULL)
       {
           // Set the cipher list to the user specified cipher list.
           if (SSL_CTX_set_cipher_list(sslContext, sslCipherSuite) == 0)
           {
               trace_SSL_BadCipherList(scs(sslCipherSuite));
         return MI_RESULT_FAILED;         return MI_RESULT_FAILED;
     }     }
       }
   
       // Disable SSL_v2 and/or SSL_v3 if requested
       if ( sslOptions & DISABLE_SSL_V2 )
       {
           options |= SSL_OP_NO_SSLv2;
       }
       if ( sslOptions & DISABLE_SSL_V3 )
       {
           options |= SSL_OP_NO_SSLv3;
       }
       if ( SSL_CTX_set_options(sslContext, options) == 0 )
       {
           trace_SSL_CannotSetOptions( options );
           return MI_RESULT_FAILED;
       }
   
     SSL_CTX_set_quiet_shutdown(sslContext, 1);     SSL_CTX_set_quiet_shutdown(sslContext, 1);
     SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);     SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
     SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);     SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
Line 1313 
Line 1496 
     ** certificate.     ** certificate.
     */     */
     {     {
           char errorBuf[256];
   
         /* load the specified server certificates */         /* load the specified server certificates */
         LOGI_CHAR(("---> SSL: Loading server certificate from: %s",          trace_SSL_LoadingServerCert(scs(OMI_GetPath(ID_PEMFILE)));
             GetPath(ID_PEMFILE)));  
  
         if (SSL_CTX_use_certificate_file(sslContext,         if (SSL_CTX_use_certificate_file(sslContext,
             GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)              OMI_GetPath(ID_PEMFILE), SSL_FILETYPE_PEM) <=0)
         {         {
             LOGE_CHAR(("---> SSL: No server certificate found in %s",              trace_SSL_NoServerCertFound(OMI_GetPath(ID_PEMFILE), GetSslErrorString(errorBuf, 256));
                 GetPath(ID_PEMFILE)));  
             SSL_CTX_free(sslContext);             SSL_CTX_free(sslContext);
             return MI_RESULT_FAILED;             return MI_RESULT_FAILED;
         }         }
Line 1333 
Line 1516 
     ** If specified, validate and load the key.     ** If specified, validate and load the key.
     */     */
     {     {
           char errorBuf[256];
   
         /* load the specified server certificates */         /* load the specified server certificates */
         LOGI_CHAR(("---> SSL: Loading certificate's private key from: %s",          trace_SSL_LoadingCertPrivateKey(scs(OMI_GetPath(ID_KEYFILE)));
             GetPath(ID_KEYFILE)));  
  
         //          /* load given private key and check for validity
         // load given private key and check for validity          */
         //          if (!_verifyPrivateKey(sslContext, OMI_GetPath(ID_KEYFILE)))
         if (!_verifyPrivateKey(sslContext, GetPath(ID_KEYFILE)))          {
         {              trace_SSL_NoServerCertFound(scs(OMI_GetPath(ID_KEYFILE)), GetSslErrorString(errorBuf, sizeof errorBuf));
             LOGE_CHAR((  
                 "---> SSL: No server certificate found in %s",  
                 GetPath(ID_KEYFILE)));  
             SSL_CTX_free(sslContext);             SSL_CTX_free(sslContext);
             return MI_RESULT_FAILED;             return MI_RESULT_FAILED;
         }         }
Line 1379 
Line 1560 
  
         if (r != MI_RESULT_OK)         if (r != MI_RESULT_OK)
         {         {
               trace_SocketClose_SetBlockingFailed();
             Sock_Close(listener);             Sock_Close(listener);
             return r;             return r;
         }         }
Line 1386 
Line 1568 
  
     /* Watch for read events on the listener socket (client connections) */     /* Watch for read events on the listener socket (client connections) */
     {     {
         Http_Listener_SocketData* h = (Http_Listener_SocketData*)calloc(1, sizeof(Http_Listener_SocketData));          Http_Listener_SocketData* h = (Http_Listener_SocketData*)PAL_Calloc(1, sizeof(Http_Listener_SocketData));
  
         if (!h)         if (!h)
         {         {
               trace_SocketClose_Http_Listener_SocketDataAllocFailed();
             Sock_Close(listener);             Sock_Close(listener);
             return MI_RESULT_FAILED;             return MI_RESULT_FAILED;
         }         }
Line 1404 
Line 1587 
  
         if (r != MI_RESULT_OK)         if (r != MI_RESULT_OK)
         {         {
               trace_SocketClose_Selector_AddHandlerFailed();
             Sock_Close(listener);             Sock_Close(listener);
             free(h);              PAL_Free(h);
             return r;             return r;
         }         }
     }     }
Line 1414 
Line 1598 
 } }
  
 MI_Result Http_New_Server( MI_Result Http_New_Server(
     Http** selfOut,      _Out_       Http**              selfOut,
     Selector* selector, /*optional, maybe NULL*/      _In_        Selector*           selector,               /* optional, maybe NULL*/
     unsigned short http_port,   /* 0 to disable */      _In_        unsigned short      http_port,              /* 0 to disable */
     unsigned short https_port,  /* 0 to disable */      _In_        unsigned short      https_port,             /* 0 to disable */
     HttpCallbackOnNewConnection callbackOnNewConnection,      _In_opt_z_  const char*         sslCipherSuite,         /* NULL to disable */
     HttpCallbackOnCloseConnection callbackOnCloseConnection,      _In_        Server_SSL_Options  sslOptions,             /* 0 for default options */
     HttpCallbackOnRequest callbackOnRequest,      _In_        OpenCallback        callbackOnNewConnection,
     void* callbackData)      _In_opt_    void*               callbackData,
       _In_opt_    const HttpOptions*  options)
 { {
     Http* self;     Http* self;
     MI_Result r;     MI_Result r;
  
     /* allocate this, inits selector */     /* allocate this, inits selector */
     r = _New_Http(selfOut, selector, callbackOnNewConnection,      r = _New_Http(selfOut, selector, callbackOnNewConnection, callbackData);
         callbackOnCloseConnection, callbackOnRequest, callbackData);  
  
     if (MI_RESULT_OK != r)     if (MI_RESULT_OK != r)
         return r;         return r;
Line 1455 
Line 1639 
         SSL_library_init();         SSL_library_init();
  
         /* create context */         /* create context */
         r = _CreateSSLContext(self);          r = _CreateSSLContext(self, sslCipherSuite, sslOptions);
  
         if (r != MI_RESULT_OK)         if (r != MI_RESULT_OK)
         {         {
Line 1476 
Line 1660 
     MI_UNUSED(https_port);     MI_UNUSED(https_port);
 #endif #endif
  
       // options
       if( NULL == options )
       {
           HttpOptions tmpOptions = DEFAULT_HTTP_OPTIONS;
           self->options = tmpOptions;
       }
       else
       {
           self->options = *options;
       }
   
     return MI_RESULT_OK;     return MI_RESULT_OK;
 } }
  
Line 1493 
Line 1688 
     if (self->internalSelectorUsed)     if (self->internalSelectorUsed)
     {     {
         /* Release selector;         /* Release selector;
         Note: selector-destory closes all sockects in a list including connector and listener */          Note: selector-destory closes all sockets in a list including connector and listener */
         Selector_Destroy(self->selector);         Selector_Destroy(self->selector);
  
         /* Shutdown the network */         /* Shutdown the network */
Line 1507 
Line 1702 
     self->magic = 0xDDDDDDDD;     self->magic = 0xDDDDDDDD;
  
     /* Free self pointer */     /* Free self pointer */
     free(self);      PAL_Free(self);
  
     return MI_RESULT_OK;     return MI_RESULT_OK;
 } }
Line 1517 
Line 1712 
     MI_Uint64 timeoutUsec)     MI_Uint64 timeoutUsec)
 { {
     /* Run the selector */     /* Run the selector */
     return Selector_Run(self->selector, timeoutUsec);      return Selector_Run(self->selector, timeoutUsec, MI_FALSE);
 }  
   
 /* sends 'ok' response with provided content;  
  if message is accepted to be sent, on return *data == null (taking memory ownership)*/  
 MI_Result Http_SendResponse(  
     Http* self,  
     void* httpConnectionHanlde,  
     int httpErrorCode,  
     Page** data)  
 {  
     Http_SR_SocketData* sendSock;  
   
     /* check params */  
     if (!self)  
         return MI_RESULT_INVALID_PARAMETER;  
   
     if (self->magic != _MAGIC)  
     {  
         LOGW((T("_SendIN_IO_thread: invalid magic!") ));  
         return MI_RESULT_INVALID_PARAMETER;  
     }  
   
     sendSock = (Http_SR_SocketData*)httpConnectionHanlde;  
   
     /* validate handler */  
   
     if (MI_RESULT_OK != Selector_ContainsHandler(  
             self->selector, (Handler*)sendSock ) )  
     {  
         LOGW((T("cannot send message: invalid handler (msg->clientID) %p\n"), sendSock));  
         return MI_RESULT_INVALID_PARAMETER;  
     }  
   
     sendSock->requestIsBeingProcessed = MI_FALSE;  
   
     sendSock->base.mask |= SELECTOR_WRITE;  
     sendSock->base.mask &= ~SELECTOR_READ;  
   
     if (data)  
     {  
         sendSock->sendPage = *data;  
         *data = 0;  
     }  
     else  
     {  
         sendSock->sendPage = 0;  
     }     }
     sendSock->httpErrorCode = httpErrorCode;  
  
     sendSock->sentSize = 0;  
     sendSock->sendingState = RECV_STATE_HEADER;  
   
     _RequestCallbackWrite(sendSock);  
   
     return MI_RESULT_OK;  
 }  
   
 /* Sets http options (mostly unit-test support) */  
 MI_Result Http_SetOptions(  
     Http* self,  
     const HttpOptions* options)  
 {  
     /* check params */  
     if (!self || !options)  
         return MI_RESULT_INVALID_PARAMETER;  
   
     if (self->magic != _MAGIC)  
     {  
         LOGW((T("Http_SetOptions: invalid magic!") ));  
         return MI_RESULT_INVALID_PARAMETER;  
     }  
   
     self->options = *options;  
     return MI_RESULT_OK;  
 }  


Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

ViewCVS 0.9.2