Пример #1
0
int StripGETRequestQueryAndFragment(char * request, unsigned int maxQueryLength)
{
   if (request==0) { errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT); return 0;}
   unsigned int length=strlen(request);
   if (length==0)  { errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT); return 0; }
   if (length>maxQueryLength) { length=maxQueryLength; }


   unsigned int i=0,fragment_pos=length;

   while ( (i<length) &&  (request[i]!='?') /*Query start character*/)
    {
        if (request[i]=='#' /*Fragment start character*/ ) { fragment_pos=i; }
        ++i;
    }

   //fprintf(stderr,"Searching for Query : Request has a %u size , fragment at pos %u/%u \n",length,fragment_pos,length);
   if (fragment_pos<length) { request[fragment_pos]=0; /*Disregard any fragments , they are for the client only.. */ }
   if (i==length)   { return 0; } //<- could not find a ..
   if (i+1>=length) { return 0; } //<- found the question mark at i BUT it is the last character so no extension is possible..!

   //char * start_of_query = &request[i+1]; // do not include ? ( question mark )

   //Null Terminate
   request[i]=0;


   //fprintf(stderr,"GET Request ( %s ) has a query inlined ( %s ) \n",request,query);
  return 1;
}
Пример #2
0
void cParser::onError(void)
{
    skipToEnd();
    char buffer[256];
    sprintf_s(buffer, 256, "行 %d : ",m_curLine+1);
    m_errorDesc = buffer;
    if (errorID() == 1)
    {
        m_errorDesc += "在尝试赋值的时候,没有得到任何可赋值的变量。";
    }
    else if (errorID() == 2)
    {
        m_errorDesc += "同一行上出现了两个变量名 :";
        m_errorDesc += m_variable;
        m_errorDesc += " 和 ";
        m_errorDesc += m_curVariable;
    }
    else if (errorID() == 3)
    {
        m_errorDesc += "非法变量名。";
    }
    else 
    {
        m_errorDesc += "未知错误。";
    }
    testOutput(m_errorDesc);
    m_curVariable.clear();
    m_variable.clear();
    setError(0);
}
Пример #3
0
unsigned int ServerThreads_DropRootUID()
{
   if (ENABLE_DROPPING_UID_ALWAYS ) { /* We fall through and change UID , as a mandatory step.. */} else
   if (ENABLE_DROPPING_ROOT_UID_IF_ROOT)
      { /*Check if we are root */
        if (getuid()>=1000) { /*Non root id , we can skip dropping our UID with this configuration..*/ return 0; }
                              //If we fell through it means we are root and dropping root when root is enabled so the code that follows will alter our uid..
      } else
      {
        if (getuid()<1000)
             {
              errorID(ASV_ERROR_RUNNING_AS_ROOT);
             }
        return 0;
      }

   char command_to_get_uid[MAX_FILE_PATH]={0};
   snprintf(command_to_get_uid,MAX_FILE_PATH,"id -u %s",USERNAME_UID_FOR_DAEMON);


   FILE * fp  = popen(command_to_get_uid, "r");
   if (fp == 0 ) { fprintf(stderr,"Failed to get our user id ( trying to drop root UID ) \n"); return 0; }

   char output[POPEN_BUFFER_SIZE]={0};
   /* Read the output a line at a time - output it. */
     unsigned int i=0;
     //Why is this needed ?
     while (fgets(output,POPEN_BUFFER_SIZE , fp) != 0)
        { ++i; /*fprintf(stderr,"\n\nline %u = %s \n",i,output);*/ break; }
    /* close */
     pclose(fp);

   int non_root_uid = atoi(output);
   if (non_root_uid<1000)
      {
        fprintf(stderr,"The user set in USERNAME_UID_FOR_DAEMON=\"%s\" is also root (his uid is %d)\n",USERNAME_UID_FOR_DAEMON,non_root_uid);
        if (CHANGE_TO_UID<1000)
            {
              errorID(ASV_ERROR_FAILED_TO_DROP_ROOT_UID);
              non_root_uid=NON_ROOT_UID_IF_USER_FAILS;
            } else
            {
              non_root_uid=CHANGE_TO_UID;
            }
      }

   fprintf(stderr,"setuid(%d);\n",non_root_uid);
   return setuid(non_root_uid); // Non Root UID :-P
}
Пример #4
0
int ReducePathSlashes_Inplace(char * filename)
{
  //This piece of code removes excess slashes from resource strings in place
  //For example the string public_html/////test.html will become public_html/test.html
  //While extra slashes cause no side effects on fopen calls etc , they interfere with the
  //hashing functions because public_html//test.html yields a different hash than public_html/test.html ..
  //This in turn means cache misses happening without any reason and the cache growing larger for files already
  //contained in it , that is why it is worth it to reduce slashes for every incoming request even if it means
  //growing the incoming string processing surface ..

  //fprintf(stderr,"ReducePathSlashes_Inplace(%s) needs thorough testing .. :P\n",filename);
  unsigned int length=strlen(filename);
  unsigned int i=0,offset=0;
     while (i+offset<length)
     {
        if ( filename[i+offset]=='/')
         {
            unsigned int z=i+offset+1;
            while ((z<length)&&(filename[z]=='/'))
            {
              ++offset;
              ++z;
            }

            if (z>i+offset+1)
            {
             //We increased the offset ..!
             ++i; // We dont want to hurt the first slash ..!
             //The next character though should be eliminated if offset changed
            }
         }

        if ( (offset>0)&&(i+offset<length) )
         {
            filename[i]=filename[i+offset];
         }
        ++i;
     }

     if (strstr(filename,"//")!=0)
     {
         errorID(ASV_ERROR_REDUCE_SLASHSES_FAILED);
     }


     if (offset>0)
     {
       //We have reduced the total slashes..!
       //Append new null termination
       filename[length-offset]=0;
       //fprintf(stderr,"String shortened to %s.. :P\n",filename);
       return 1;
     }

 //fprintf(stderr,"String (%s) was not changed \n",filename);
 return 0;
}
Пример #5
0
int setSocketTimeouts(int clientSock)
{
 int errorSettingTimeouts = 1;

#if USE_TIMEOUTS
 struct timeval timeout; //We dont need to initialize here , since we initialize on the next step
 timeout.tv_sec = (unsigned int) varSocketTimeoutREAD_seconds; timeout.tv_usec = 0;
 if (setsockopt (clientSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
    { errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT); errorSettingTimeouts=0; }

 timeout.tv_sec = (unsigned int) varSocketTimeoutWRITE_seconds; timeout.tv_usec = 0;
 if (setsockopt (clientSock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
    { errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT); errorSettingTimeouts=0; }
#else
    #error "It is a terrible idea not to use socket timeouts , this will make the webserver susceptible to DoS attacks..!"
#endif // USE_TIMEOUTS

 return errorSettingTimeouts;
}
Пример #6
0
int getSocketIPAddress(struct AmmServer_Instance * instance , int clientSock , char * ipstr , unsigned int ipstrLength,unsigned int * port)
{
  //Lets find out who we are talking to , and if we want to deny him service or not..!
  socklen_t len=0;
  struct sockaddr_storage addr;

  ipstr[0]=0;
   strcpy(ipstr,"0.0.0.0");
  *port=0;

  len = sizeof addr;
  if ( getpeername(clientSock, (struct sockaddr*)&addr, &len) == 0 )
 {
  const char * resolveResult = 0;
  // deal with both IPv4 and IPv6:
  if (addr.ss_family == AF_INET)
  {
    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
    *port = ntohs(s->sin_port);
    resolveResult = inet_ntop(AF_INET, &s->sin_addr, ipstr,ipstrLength);
  } else
  { // AF_INET6
    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
    *port = ntohs(s->sin6_port);
    resolveResult = inet_ntop(AF_INET6, &s->sin6_addr, ipstr,ipstrLength);
  }

  if (resolveResult == 0)
  {
   errorID(ASV_ERROR_INNETOP_FAILED); //This could be a reason to drop this connection!
    switch ( errno )
    {
     case EAFNOSUPPORT :   warning("The af argument is invalid.\n");                              break;
     case ENOSPC       :   warning("The size of the inet_ntop() result buffer is inadequate.\n"); break;
    }
  }

  fprintf(stderr,"%s: Peer IP address: %s , port %d \n", instance->instanceName , ipstr,*port);
 } else
 {
   warning("Could not get peer name..!"); //This could be a reason to drop this connection!
   switch ( errno )
   {
     case EBADF    : warning("The argument sockfd is not a valid descriptor.");                                       break;
     case EFAULT   : warning("The addr argument points to memory not in a valid part of the process address space."); break;
     case EINVAL   : warning("addrlen is invalid (e.g., is negative).");                                              break;
     case ENOBUFS  : warning("Insufficient resources were available in the system to perform the operation.");        break;
     case ENOTCONN : warning("The socket is not connected.");                                                         break;
     case ENOTSOCK : warning("The argument sockfd is a file, not a socket.");                                         break;
   };
   return 0;
 }

 return  1; // <- TODO add IPv4 , IPv6 IP here
}
Пример #7
0
int _GENERIC_cpy(const char * what2copy,unsigned int what2copySize,char * where2copy,unsigned int maxSizeWhere2Copy)
{
  if (what2copy==0) { return 0; }
  if (where2copy==0) { return 0; }
  if (what2copySize+1>maxSizeWhere2Copy)
     {
       errorID(ASV_ERROR_NOT_ENOUGH_MEMORY_ALLOCATED);
       return 0;
     }

  snprintf(where2copy,maxSizeWhere2Copy,"%s",what2copy);
  return 1;
}
Пример #8
0
//You should use AmmCLient instead of this shitty code..!
char * RequestHTTPWebPage(struct AmmServer_Instance * instance,char * hostname,unsigned int port,char * filename,unsigned int max_content)
{
  int sockfd;
  struct hostent *he=0;
  struct sockaddr_in their_addr;

  if ((he=gethostbyname(hostname)) == 0) { fprintf(stderr,"Error getting host (%s) by name \n",hostname); return 0; } else
                                         { printf("Client-The remote host is: %s\n",hostname); }

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { errorID(ASV_ERROR_FAILED_TO_SOCKET); return 0; } else
                                                        { printf("Client socket ok\n");                   }

    // host byte order
    their_addr.sin_family = AF_INET;
    // short, network byte order
    printf("Server-Using %s:%u...\n",hostname,port);
    their_addr.sin_port = htons(port);
    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
    // zero the rest of the struct
    memset(&(their_addr.sin_zero), 0 , 8); // '\0'

   if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { errorID(ASV_ERROR_FAILED_TO_CONNECT);  return 0; } else
                                                                                      { printf("Starting Request for filename %s \n",filename); }

#if USE_TIMEOUTS
    struct timeval timeout;
    timeout.tv_sec = (unsigned int) varSocketTimeoutREAD_seconds; timeout.tv_usec = 0;
    if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { fprintf(stderr,"Warning : Could not set socket Receive timeout \n"); }

    timeout.tv_sec = (unsigned int) varSocketTimeoutWRITE_seconds; timeout.tv_usec = 0;
    if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { fprintf(stderr,"Warning : Could not set socket Send timeout \n"); }
#else
    #error "It is a terrible idea not to use socket timeouts , this will make the webserver susceptible to DoS attacks..!"
#endif // USE_TIMEOUTS


    unsigned long bufferSize = (max_content+1) * sizeof(char);
    char * buffer = (char*) malloc(bufferSize);
    if (buffer!=0)
    {
      snprintf(buffer,max_content,"GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n",filename,hostname);

      struct HTTPTransaction transaction={0}; //This is a dummy call and does not need ASRV_StartSession
      transaction.clientSock = sockfd;
      int opres =  ASRV_Send(instance,&transaction,buffer,strlen(buffer),MSG_WAITALL|MSG_NOSIGNAL);  //Send filesize as soon as we've got it

      if (opres<=0) { fprintf(stderr,"Error Sending Request data\n"); } else
      {
        buffer[0]=0;
        opres = recv(sockfd,buffer,max_content,0);
        if (opres<=0) { fprintf(stderr,"Error Receiving Request data\n"); }
      }

      safeFree(buffer,bufferSize);
    }

    close(sockfd);

  /** @bug : Check for success or failure on RequestHTTPWebPage and return an appropriate return value */
  return 0;
}
Пример #9
0
int GetContentTypeForExtension(const char * theextension,char * content_type,unsigned int contentTypeLength)
{
  //fprintf(stderr,"Resolving Extension %s , length %u \n",theextension,theextensionLength );
  if (contentTypeLength<29)
  {
    errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT);
    fprintf(stderr,"GetContentTypeForExtension called with a very small buffer ( %u bytes )  \n",contentTypeLength );
    return 0;
  }


  unsigned int theextensionLength = strlen(theextension);

  //http://www.iana.org/assignments/media-types/text/index.html
  unsigned int ext=scanFor_textFiles(theextension,theextensionLength);
  switch (ext)
  {
    case TEXTFILES_HTML  :  strcpy(content_type,"text/html"); content_type[9]=0; return 1; break;
    case TEXTFILES_HTM   :  strcpy(content_type,"text/html"); content_type[9]=0; return 1; break;
    case TEXTFILES_CSS   :  strcpy(content_type,"text/css");  content_type[8]=0; return 1; break;
    case TEXTFILES_TXT   :  strcpy(content_type,"text/txt");  content_type[8]=0; return 1; break;
    case TEXTFILES_DOC   :  strcpy(content_type,"text/doc");  content_type[8]=0; return 1; break;
    case TEXTFILES_RTF   :  strcpy(content_type,"text/rtf");  content_type[8]=0; return 1; break;
    case TEXTFILES_ODF   :  strcpy(content_type,"text/odf");  content_type[8]=0; return 1; break;
    case TEXTFILES_ODT   :  strcpy(content_type,"text/odt");  content_type[8]=0; return 1; break;
  };

  //http://www.iana.org/assignments/media-types/image/index.html
  ext=scanFor_imageFiles(theextension,theextensionLength);
  switch (ext)
  {
   case IMAGEFILES_GIF  :  strcpy(content_type,"image/gif");  content_type[9]=0; return 1; break;
   case IMAGEFILES_PNG  :  strcpy(content_type,"image/png");  content_type[9]=0; return 1; break;
   case IMAGEFILES_JPG  :
   case IMAGEFILES_JPEG :  strcpy(content_type,"image/jpg");  content_type[9]=0; return 1; break;
   case IMAGEFILES_WEBP :  strcpy(content_type,"image/webp"); content_type[10]=0; return 1; break;
   case IMAGEFILES_BMP  :  strcpy(content_type,"image/bmp");  content_type[9]=0; return 1; break;
   case IMAGEFILES_TIFF :  strcpy(content_type,"image/tiff"); content_type[10]=0; return 1; break;
   case IMAGEFILES_DIB  :  strcpy(content_type,"image/dib");  content_type[9]=0; return 1; break;
   case IMAGEFILES_RLE  :  strcpy(content_type,"image/rle");  content_type[9]=0; return 1; break;
   case IMAGEFILES_J2C  :  strcpy(content_type,"image/j2c");  content_type[9]=0; return 1; break;
   case IMAGEFILES_ICO  :  strcpy(content_type,"image/ico");  content_type[9]=0; return 1; break;
   case IMAGEFILES_PPM  :  strcpy(content_type,"image/ppm");  content_type[9]=0; return 1; break;
   case IMAGEFILES_PNM  :  strcpy(content_type,"image/pnm");  content_type[9]=0; return 1; break;
   case IMAGEFILES_RAW  :  strcpy(content_type,"image/raw");  content_type[9]=0; return 1; break;
   case IMAGEFILES_SVG  :  strcpy(content_type,"image/svg+xml"); content_type[13]=0; return 1; break;
  };

//http://www.iana.org/assignments/media-types/video/index.html
  ext=scanFor_videoFiles(theextension,theextensionLength);
  switch (ext)
  {
   case VIDEOFILES_AVI      :  strcpy(content_type,"video/mp4");   content_type[9]=0; return 1; break;
   case VIDEOFILES_MPEG4    :  strcpy(content_type,"video/mp4");   content_type[9]=0; return 1; break;
   case VIDEOFILES_MPEG     :  strcpy(content_type,"video/mp4");   content_type[9]=0; return 1; break;
   case VIDEOFILES_MP4      :  strcpy(content_type,"video/mp4");   content_type[9]=0; return 1; break;
   case VIDEOFILES_OGV      :  strcpy(content_type,"video/ogv");   content_type[9]=0; return 1; break;
   case VIDEOFILES_WEBM     :  strcpy(content_type,"video/webm");  content_type[10]=0; return 1; break;
   case VIDEOFILES_MKV      :  strcpy(content_type,"video/mkv");   content_type[9]=0; return 1; break;
   case VIDEOFILES_3GP      :  strcpy(content_type,"video/3gp");   content_type[9]=0; return 1; break;
   case VIDEOFILES_H263     :  strcpy(content_type,"video/h263");  content_type[10]=0;return 1; break;
   case VIDEOFILES_H264     :  strcpy(content_type,"video/h264");  content_type[10]=0;return 1; break;
   case VIDEOFILES_FLV      :  strcpy(content_type,"video/x-flv"); content_type[11]=0; return 1; break;
  };

//http://www.iana.org/assignments/media-types/audio/index.html
  ext=scanFor_audioFiles(theextension,theextensionLength);
  switch (ext)
  {
   case AUDIOFILES_MP3   :  strcpy(content_type,"audio/mp3");   content_type[9]=0; return 1; break;
   case AUDIOFILES_WAV   :  strcpy(content_type,"audio/wav");   content_type[9]=0; return 1; break;
   case AUDIOFILES_MID   :  strcpy(content_type,"audio/mid");   content_type[9]=0; return 1; break;
   case AUDIOFILES_OGG   :  strcpy(content_type,"audio/ogg");   content_type[9]=0; return 1; break;
   case AUDIOFILES_VOC   :  strcpy(content_type,"audio/voc");   content_type[9]=0; return 1; break;
   case AUDIOFILES_AU    :  strcpy(content_type,"audio/au");    content_type[8]=0; return 1; break;
  };

//http://www.iana.org/assignments/media-types/application/index.html
  ext=scanFor_applicationFiles(theextension,theextensionLength);
  switch (ext)
  {
   case APPLICATIONFILES_EXE  :
   case APPLICATIONFILES_DLL  :
   case APPLICATIONFILES_SCR  :
   case APPLICATIONFILES_CPL  :  strcpy(content_type,"application/exe");                  content_type[15]=0; return 1; break;
   case APPLICATIONFILES_SWF  :  strcpy(content_type,"application/x-shockwave-flash");    content_type[29]=0; return 1; break;
   case APPLICATIONFILES_PDF  :  strcpy(content_type,"application/pdf");                  content_type[15]=0; return 1; break;
  };


  ext=scanFor_archiveFiles(theextension,theextensionLength);
  switch (ext)
  {
   case   ARCHIVEFILES_GZ        :  strcpy(content_type,"application/gzip");    content_type[16]=0; return 1; break;
   case   ARCHIVEFILES_TAR       :  strcpy(content_type,"application/x-tar");   content_type[17]=0; return 1; break;
   case   ARCHIVEFILES_TGZ       :  strcpy(content_type,"application/gnutar");  content_type[18]=0; return 1; break;
   case   ARCHIVEFILES_ZIP       :  strcpy(content_type,"application/zip");     content_type[15]=0; return 1; break;
   case   ARCHIVEFILES_JAR       :
   case   ARCHIVEFILES_7Z        :
   case   ARCHIVEFILES_AR        :
   case   ARCHIVEFILES_BZ2       :
   case   ARCHIVEFILES_CBZ       :
   case   ARCHIVEFILES_CPIO      :
   case   ARCHIVEFILES_ISO       :
   case   ARCHIVEFILES_LZMA      :
   case   ARCHIVEFILES_TAR_7Z    :
   case   ARCHIVEFILES_TAR_Z     :
   case   ARCHIVEFILES_TAR_GZ    :
   case   ARCHIVEFILES_TAR_BZ2   :
   case   ARCHIVEFILES_TAR_BZ    :
   case   ARCHIVEFILES_TAR_LZ    :
   case   ARCHIVEFILES_TAR_LZMA  :
   case   ARCHIVEFILES_TAR_XZ    :
   case   ARCHIVEFILES_XZ        :  strcpy(content_type,"application/octet-stream");      content_type[24]=0; return 1; break;
  };

 fprintf(stderr,"Could not find extension type for extension %s \n",theextension);
 return 0;
}
Пример #10
0
void * ServeClientAfterUnpackingThreadMessage(void * ptr)
{
  // We first have to store the context variables we got through our struct PassToHTTPThread
  // so we first need to do that
  struct PassToHTTPThread * context = (struct PassToHTTPThread *) ptr;
  if (context->keep_var_on_stack!=1)
   {
     errorID(ASV_ERROR_FAILED_TO_PASS_THREAD_CONTEXT);
     fprintf(stderr,"Bad new thread context is pointing to %p\n",context);
     return 0;
   }

  //This is the structure that holds all the state of the current ServeClient transaction
  struct AmmServer_Instance * instance = context->instance;
  struct HTTPTransaction transaction={0}; // This should get free'ed once it isn't needed any more see FreeHTTPHeader call!
  //int close_connection=0; // <- if this is set it means Serve Client must stop

  transaction.instance=instance;
  //memset(&transaction->incomingHeader,0,sizeof(struct HTTPHeader));
  transaction.incomingHeader.headerRAW=0;
  transaction.incomingHeader.headerRAWSize=0;

  // In order for each thread to (in theory) be able to serve a different virtual website
  // we declare the webserver_root etc here and we copy the value from the thread spawning function
  // This creates a little code clutter but it is for the best..!
  transaction.prespawnedThreadFlag=context->pre_spawned_thread;
  transaction.clientSock=context->clientsock;
  transaction.threadID = context->thread_id;


  if (!transaction.prespawnedThreadFlag)
   {
     int i = pthread_detach(instance->threads_pool[transaction.threadID]);
     if (i!=0)
     {
       switch (i)
       {
         case EINVAL : warning("While trying to detach thread , The implementation has detected that the value specified by thread does not refer to a joinable thread."); break;
         case ESRCH : warning("While trying to detach thread , No thread could be found corresponding to that specified by the given thread ID."); break;
       };
     }
   }

  fprintf(stderr,"Now signaling we are ready (%u)\n",transaction.threadID);
  context->keep_var_on_stack=2; //This signals that the thread has processed the message it received..!
  fprintf(stderr,"Passing message to HTTP thread is done (%u)\n",transaction.threadID);

  ASRV_StartSession(instance,&transaction);

    //int i=
    ServeClientInternal(instance,&transaction);

  ASRV_StopSession(instance,&transaction);

/*
  //Removed to reduce spam..!
  if (i)
  {
    //SUCCESS
  } else
  {
    //FAILURE
    warning("Could not successfully serve client..");
  }
*/

  return 0;
}
Пример #11
0
int ServeClientInternal(struct AmmServer_Instance * instance , struct HTTPTransaction * transaction)
{

  if (instance==0) { errorID(ASV_ERROR_INSTANCE_NOT_ALLOCATED); return 0; } else
                   { /*fprintf(stderr,"ServeClient instance pointing @ %p \n",instance);*/ }

  if (!setSocketTimeouts(transaction->clientSock))
   {
    errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT);
    fprintf(stderr,"This means something weird is going on , skipping everything");
    return 0;
   }

  transaction->clientListID = findOutClientIDOfPeer(instance ,transaction->clientSock);

  //----------------------------- ---------------------------- ----------------------------
  // Check if client is banned
  //----------------------------- ---------------------------- ----------------------------
  int clientIsBanned = clientList_isClientBanned(instance->clientList,transaction->clientListID);
  //----------------------------- ---------------------------- ----------------------------
  if (!clientIsBanned)
  {
     //If client is ok go ahead to serve him..
     unsigned int keepAliveShots = 1;
     while ( ( ServeClientKeepAliveLoop(instance,transaction) ) && (instance->server_running) )
    {
      //fprintf(stderr,"Another KeepAlive Loop Served ( %u ) \n",keepAliveShots);
      ++keepAliveShots;
      clientIsBanned = clientList_isClientBanned(instance->clientList,transaction->clientListID);
      if (clientIsBanned)
      {
       warningID(ASV_WARNING_CLIENT_DENIED_ACCESS);
       SendErrorCodeHeader(instance,transaction,403 /*Forbidden*/,"403.html",instance->templates_root);
       break;
      }
    }
  }
  //----------------------------- ---------------------------- ----------------------------

  //fprintf(stderr,"Done with client / Closing Socket ( %u )  ..\n",transaction->clientSock);
  close(transaction->clientSock);
//  shutdown(transaction->clientSock,SHUT_RDWR);


  if (transaction->incomingHeader.headerRAW!=0)
  {
   //fprintf(stderr,"Done with client / Freeing incoming memory..\n");
   safeFree(transaction->incomingHeader.headerRAW,transaction->incomingHeader.headerRAWSize);
   transaction->incomingHeader.headerRAW=0;
  }

  //fprintf(stderr,"closed\n");

  if (!transaction->prespawnedThreadFlag)
   { //If we are running in a prespawned thread it is wrong to count this thread as a *dynamic* one that just stopped !
     //Clear thread id handler and we can gracefully exit..! ( LOCKLESS OPERATION)
     if (instance->threads_pool[transaction->threadID]==0) { fprintf(stderr,"While exiting thread , thread_pool id[%u] is already zero.. This could be a bug ..\n",transaction->threadID); }
     instance->threads_pool[transaction->threadID]=0;
     ++instance->CLIENT_THREADS_STOPPED;

     //We also only want to stop the thread if itsnot prespawned !
     //fprintf(stderr,"Exiting Thread\n");
     //pthread_join(instance->threads_pool[transaction->threadID],0);
     //pthread_exit(0);


     //This should make the thread release all of its resources (?)
     pthread_detach(pthread_self());
   }

  return 0;
}
Пример #12
0
int ServeClientKeepAliveLoop(struct AmmServer_Instance * instance,struct HTTPTransaction * transaction)
{
  //Remember the IP of this client..
  getSocketIPAddress(instance,transaction->clientSock,transaction->ipStr,MAX_IP_STRING_SIZE,&transaction->port);

   //We have our connection / instancing /etc covered if we are here
   //In order to serve our client we must first receive the request header , so we do it now..!
   int httpHeaderReceivedWithNoProblems = receiveAndHandleHTTPHeaderSentByClient(instance,transaction);

   if (!httpHeaderReceivedWithNoProblems)
   {
     if (transaction->clientDisconnected)
     {
      warningID(ASV_WARNING_CONNECTION_CLOSED_WHILE_KEEPALIVE);
     } else
     {
      /*We got a bad http request so we will rig it to make server emmit the 400 message*/
      errorID(ASV_ERROR_FAILED_TO_RECEIVE_HEADER);
      SendErrorFile(instance,transaction,400);
      logError(instance,transaction,400,"400.html");
     }
      return 0;
   }
      else
   if (!clientList_isClientAllowedToUseResource(instance->clientList,transaction->clientListID,transaction->incomingHeader.resource))
   {
     //Client is forbidden but he is not IP banned to use resource ( already opened too many connections or w/e other reason )
     //Doesnt have access to the specific file , etc..!
     warningID(ASV_WARNING_CLIENT_DENIED_ACCESS);
     SendErrorCodeHeader(instance,transaction,403 ,"403.html",instance->templates_root);
     logError(instance,transaction,403,"403.html");
     return 0;
   } else
   if ((instance->settings.PASSWORD_PROTECTION)&&(!transaction->incomingHeader.authorized))
   {
     errorID(ASV_ERROR_UNAUTHORIZED_REQUEST);
     respondToClientRequestingAuthorization(instance,transaction);
     return 0;
   }
     else
   { // Not a Bad request Start
      //This is a hack and should be probably be changed..!
      if ( ( transaction->incomingHeader.requestType==POST ) && (instance->settings.ENABLE_POST) && (MASTER_ENABLE_POST) )
       {

         fprintf(stderr,GREEN "POST HEADER : %lu length \n %s \n" NORMAL,transaction->incomingHeader.ContentLength,transaction->incomingHeader.headerRAW);
         //TODO ADD Here a possibly rfc1867 , HTTP POST FILE compatible (multipart/form-data) recv handler..
         //TODO TODO TODO

         fprintf(stderr,"Found a POST query %lu bytes long , %s \n",transaction->incomingHeader.POSTrequestSize, transaction->incomingHeader.POSTrequest);
         warningID(ASV_WARNING_PRETENDING_IT_IS_A_GET_REQUEST);
         //Will now pretend that we are a GET request for the rest of the page to be served nicely
         transaction->incomingHeader.requestType=GET;
       }


     if (
          (transaction->incomingHeader.requestType==GET)  ||
          (transaction->incomingHeader.requestType==HEAD) ||
          (transaction->incomingHeader.requestType==POST)
        )
     {
      char servefile[(MAX_FILE_PATH*2)+1]={0}; // Since we are strcat-ing the file on top of the webserver_root it is only logical to
      // reserve space for two MAX_FILE_PATHS they are a software security limitation ( system max_path is much larger ) so its not a problem anywhere..!
      int resource_is_a_directory=0,resource_is_a_file=0,resource_is_a_template=0,generate_directory_list=0;

      /*!
             PART 1 : Sense what we want to serve , and set the flags
             resource_is_a_directory , resource_is_a_file , generate_directory_list
             accordingly..!
      */

      decideAboutHowToHandleRequestedResource
            (
              instance,
              transaction,
              servefile,
              &resource_is_a_directory,
              &resource_is_a_file ,
              &resource_is_a_template ,
              &generate_directory_list
            );

      /*!
             PART 2 : The flags
             resource_is_a_directory , resource_is_a_file , generate_directory_list
             have been set to the correct ( :P ) value so all we have to do now is serve the correct repsonse..!
      */
     if (resource_is_a_template)
     {
         //We have a specific request for a file ( transaction->incomingHeader.resource )
         fprintf(stderr,"It is a template request for %s ..!\n",servefile);
             // ------------------------------------------------------
             // ------------------------------------------------------
             // ------------------------------------------------------
             if (
                  SendEmbeddedFile
                      (
                         instance,
                         transaction,
                         servefile  // -- Log What was asked to be served
                      )
                )
                {
                  logSuccess(instance,transaction,200,servefile);
                }
                 else
                {
                 //We where unable to serve request , closing connections..\n
                 errorID(ASV_ERROR_UNABLE_TO_SERVE_TEMPLATE);
                 return 0;
                }
             // ------------------------------------------------------
             // ------------------------------------------------------
             // ------------------------------------------------------
     }
       else
     if (generate_directory_list)
     {
       respondToClientBySendingAGeneratedDirectoryList(instance,transaction,servefile);
       return 0;
     }
        else
      if  (resource_is_a_file)
      {
         //We have a specific request for a file ( transaction->incomingHeader.resource )
         //fprintf(stderr,"It is a file request for %s ..!\n",servefile);
             // ------------------------------------------------------
             // ------------------------------------------------------
             // ------------------------------------------------------
             if (
                  SendFile
                      (
                         instance,
                         transaction,
                         servefile,  // -- Log What was asked to be served
                         0 // <- We dont want to force an error code!
                      )
                )
                {
                  logSuccess(instance,transaction,200,servefile);
                }
                 else
                {
                 //We where unable to serve request , closing connections..\n
                 errorID(ASV_ERROR_UNABLE_TO_SERVE_REQUEST);
                 return 0;
                }
             // ------------------------------------------------------
             // ------------------------------------------------------
             // ------------------------------------------------------
      }
       else
     {
        fprintf(stderr,"404 not found..!!\n");
        SendErrorFile(instance,transaction,404);
        logError(instance,transaction,404,servefile);
        return 0;
     }
   } else
     if (transaction->incomingHeader.requestType==BAD)
           { //In case some of the security features of the server sensed a BAD! request we should log it..
            warningID(ASV_WARNING_PREDATORY_REQUST);
            //TODO : call -> int ErrorLogAppend(char * IP,char * DateStr,char * Request,unsigned int ResponseCode,unsigned long ResponseLength,char * Location,char * Useragent)
            SendErrorFile(instance,transaction,400);
            logError(instance,transaction,400,"400.html");
            return 0;
           } else
          if (transaction->incomingHeader.requestType==NONE)
           { //We couldnt find a request type so it is a weird input that doesn't seem to be HTTP based
            warningID(ASV_WARNING_UNRECOGNIZED_REQUEST);
            SendErrorFile(instance,transaction,400);
            logError(instance,transaction,400,"400.html");
            return 0;
           } else
           { //The request we got requires not implemented functionality , so we will admit not implementing it..! :P
            warningID(ASV_WARNING_NOTIMPLEMENTED_REQUEST);
            SendErrorFile(instance,transaction,501);
            logError(instance,transaction,501,"501.html");
            return 0;
           }
   } // Not a Bad request END

    clientList_signalClientStoppedUsingResource(instance->clientList,transaction->clientListID,transaction->incomingHeader.resource); // This in order for client_list to correctly track client behaviour..!


  if ( transaction->incomingHeader.headerRAW!=0 )
        {
          safeFree(transaction->incomingHeader.headerRAW,transaction->incomingHeader.headerRAWSize);
          transaction->incomingHeader.headerRAW=0;
        }
  //We are done with request!


  if (!transaction->incomingHeader.keepalive) { return 0; } // Close_connection controls the receive "keep-alive" loop
  //If we are on a keepalive streak , then go on !
  return 1;
}
Пример #13
0
void RDSocket::errorData(int error)
{
  emit errorID(error,id_num);
}