Exemple #1
0
void onClientReadable( aeEventLoop *el , int connfd , void *privdata , int mask )
{
	
	appnetServer *serv = servG;
	ssize_t nread;
	unsigned int readlen,rcvbuflen,datalen;
	int worker_id = servG->connlist[connfd].worker_id;
	int thid = servG->connlist[connfd].reactor_id;
	char buffer[TMP_BUFFER_LENGTH];
	
	while (1)
	{
		
		nread = 0;
		memset( &buffer , 0 , sizeof( buffer ) );
		nread = read( connfd , &buffer , sizeof( buffer ) );
		
		if (nread == -1 && errno == EAGAIN)
		{
			return; /* No more data ready. */
		}
		
		if (nread == 0)
		{
			onCloseByClient( el , privdata , serv , &serv->connlist[connfd] );
			return; /* Close event */
		}
		else if (nread > 0)
		{
			
			/* Append client recv_buffer */
			servG->connlist[connfd].recv_buffer =
					sdscatlen( servG->connlist[connfd].recv_buffer , &buffer , nread );
			
			int ret =
					parseRequestMessage( connfd , servG->connlist[connfd].recv_buffer ,
							sdslen( servG->connlist[connfd].recv_buffer ) );
			
			if (ret == BREAK_RECV)
			{
				int complete_length = servG->reactor_threads[thid].hh->complete_length;
				
				if (complete_length > 0)
				{
					sdsrange( servG->connlist[connfd].recv_buffer , complete_length , -1 );
				}
				else
				{
					sdsclear( servG->connlist[connfd].recv_buffer );
				}
				break;
				
			}
			else if (ret == CONTINUE_RECV)
			{
				continue;
				
			}
			else if (ret == CLOSE_CONNECT)
			{
				freeClient( &servG->connlist[connfd] );
				return;
			}
			return;
		}
		else
		{
			printf( "Recv Errno=%d,Err=%s \n" , errno , strerror( errno ) );
		}
	}
}
void* workerThread(void* args)
{
  int client_sd = *((int*)args);
  int tid = pthread_self();

  //debug
  printf("%sAccepted client_sd: %d, tid: %d%s\n", BG_GREEN, client_sd, tid, DEFAULT);

  // Flags for the loop
  int server_sd;
  int server_sd_reusable = 0;
  int server_response_has_no_body;
  int is_case_4;
  int file_already_cached;

  while(1)
  {
    // Initialize flags
    server_response_has_no_body = 0;
    is_case_4 = 0;
    file_already_cached = 0;

    // Read HTTP Request from the client
    char clientRequest[MAX_REQUEST_SIZE];
    strcpy(clientRequest, "");
    int bytesReceived = recv(client_sd, clientRequest, sizeof(clientRequest), 0);
    if(bytesReceived < 0)
    {
      printf("%sreceive error: %s (Errno:%d)%s\n",BG_RED, strerror(errno), errno, DEFAULT);
      pthread_exit(0);
    }
    else if (bytesReceived == 0)
    {
      printf("%stid %d: Client closed the connection. %s\n", BG_RED, tid, DEFAULT);
      pthread_exit(0);
    }

    //debug
    printf("%s=== clientRequest ===%s\n", BG_YELLOW, DEFAULT);
    printf("/%s%s%s/\n",BG_BLUE, clientRequest, DEFAULT);
    printf("%s=== End of clientRequest ===%s\n", BG_YELLOW, DEFAULT);

    // Parse the HTTP Request to struct requestAttributes
    struct requestAttributes clientRequestAttributes = parseRequestMessage(clientRequest);

    printf("%sGOOGLE ANALYTICS%s\n", BG_RED, DEFAULT);
    // If server_sd can be reused, reuse it
    // Else, establish a connection to server
    if (server_sd_reusable)
      printf("Server sd is reusable. Reuse server_sd: /%s%d%s/ now. \n", BG_PURPLE, server_sd, DEFAULT);
    else
      server_sd = connectToServer(clientRequestAttributes.Host, clientRequestAttributes.port);
    server_sd_reusable = 1;

    char buf[MAX_REQUEST_SIZE];
    strcpy(buf, clientRequest);

    //debug
    printRequestAttributes(&clientRequestAttributes);

    // If the method is not GET, simply ignore it
    if (clientRequestAttributes.methodNotGET)
    {
      printf("%sIgnored a non-GET request.%s\n", BG_PURPLE, DEFAULT);
      continue;
    }

    // If the file type is not the ones that need caching,
    // simply forwards the request to the web server
    if (!clientRequestAttributes.typeNeedsCaching)
    {
      printf("%sThe request file type does not need caching. Simply forward the request to server now.%s\n", BG_PURPLE, DEFAULT);
      int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
      printf("Sent /%s%d%s/ bytes to the server. \n", BG_PURPLE, byteSent, DEFAULT);
      if (byteSent < 0)
      {
        printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
        continue;
      }
    }
    else
    {
      // If the file is not cached in MYPROXY,
      // simply forwards it to the web server
      if (getFileModificationTime(clientRequestAttributes.URL) == -1)
      {
        printf("%sThe file is not cached on the proxy. Simply forward the request to server now. %s\n", BG_PURPLE, DEFAULT);
        int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
        if (byteSent < 0)
        {
          printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
          continue;
        }
      }
      else
      {
        file_already_cached = 1;

        // Here goes the four cases
        int caseNumber;
        if (clientRequestAttributes.noCache)
        {
          if (clientRequestAttributes.IMS == 0)
            caseNumber = 3;
          else
            caseNumber = 4;
        }
        else
        {
          if (clientRequestAttributes.IMS == 0)
            caseNumber = 1;
          else
            caseNumber = 2;
        }

        //debug
        printf("%scaseNumber is: %d%s\n", BG_PURPLE, caseNumber, DEFAULT);

        // didn't use switch since I fear to mess up
        // the break in switch with the break in while
        if (caseNumber == 1)
        {
          // Case 1:
          // Proxy directly respond the client with the cache
          if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
            break;

          goto oneLoopisDone;
        }

        if (caseNumber == 2)
        {
          // Case 2:
          // If IMS is later than LMT of the cached web object,
          // just respond 304
          // else, respond the client with 200 and the web object
          if (clientRequestAttributes.IMS > getFileModificationTime(clientRequestAttributes.URL))
          {
            char block[512];
            sprintf(block, "HTTP/1.1 304 Not Modified\r\n\r\n");
            if (send(client_sd, block, strlen(block), MSG_NOSIGNAL) <= 0)
              break;
            server_response_has_no_body = 1;
          }
          else
            if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
              break;

          goto oneLoopisDone;
        }

        if (caseNumber == 3)
        {
          // Case 3:
          // Add If-Modified-Since: *LMT* header Line to the client Request
          // and then forward it to server
          time_t LMT = getFileModificationTime(clientRequestAttributes.URL);
          char timeString[50];
          getTimeStringfromRawTime(timeString, LMT);
          char* headerEnding = strstr(buf, "\r\n\r\n");
          *headerEnding = '\0';
          sprintf(headerEnding, "\r\nIf-Modified-Since: %s\r\n\r\n", timeString);

          //debug
          printf("%s=== case 3 buf ===%s\n", BG_YELLOW, DEFAULT);
          printf("/%s%s%s/\n", BG_BLUE, buf, DEFAULT);
          printf("%s=== End of case 3 buf ===%s\n", BG_YELLOW, DEFAULT);

          int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
          if (byteSent < 0)
          {
            printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
            continue;
          }
        }

        if (caseNumber == 4)
        {
          // Case 4:
          // If IMS is later than LMT of the cached web object,
          // simply forwards it to the web server
          // Else, edit If-Modified-Since: ... header Line of the client request
          // edit the date to LMT
          // and then forward it to the web server
          is_case_4 = 1;

          time_t LMT = getFileModificationTime(clientRequestAttributes.URL);
          if (clientRequestAttributes.IMS < LMT)
          {
            char* pointerToIMS = strstr(buf, "If-Modified-Since");
            char* pointerToLatterPart = strstr(pointerToIMS, "\r\n");
            char latterPart[MAX_REQUEST_SIZE];
            strcpy(latterPart, pointerToLatterPart);
            pointerToIMS+=19; // Maybe problematic?
            *pointerToIMS = '\0';
            char timeString[50];
            getTimeStringfromRawTime(timeString, LMT);
            strcat(buf, timeString);
            strcat(buf, latterPart);

            //debug
            printf("%s=== case 4 buf ===%s\n", BG_YELLOW, DEFAULT);
            printf("/%s%s%s/\n", BG_BLUE, buf, DEFAULT);
            printf("%s=== End of case 4 buf ===%s\n", BG_YELLOW, DEFAULT);
          }

          int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
          if (byteSent < 0)
          {
            printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
            continue;
          }
        }
      }
    }

    // Now receive server's HTTP Response's header
    char receiveBuffer[MAX_RESPONSE_SIZE];
    memset(receiveBuffer, 0, sizeof(receiveBuffer));
    char* receiveBufferPtr = receiveBuffer;

    printf("%sWaiting for the server's response...%s\n", BG_PURPLE, DEFAULT);

    // Receive byte by byte until an \r\n\r\n is found
    while(1)
    {
      bytesReceived = recv(server_sd, receiveBufferPtr, 1, 0);
      if (bytesReceived < 0)
      {
        printf("%sreceive HTTP response error%s\n", BG_RED, DEFAULT);
        break;
      }

      //debug
      else if (bytesReceived == 0)
      {
        printf("%sServer Closed the connection%s\n", BG_RED, DEFAULT);
        break; // Maybe problematic
      }
      else
      {
        //printf("%sReceived one byte%s ", BG_PURPLE, DEFAULT);

        if (strstr(receiveBuffer, "\r\n\r\n") != NULL)
        break;
        receiveBufferPtr++;
      }
    }
    receiveBufferPtr++;
    *receiveBufferPtr = '\0';

    //debug
    printf("\n%s=== server's response's header ===%s\n", BG_YELLOW, DEFAULT);
    printf("/%s%s%s/\n", BG_BLUE, receiveBuffer, DEFAULT);
    printf("%s=== End of server's response's header ===%s\n", BG_YELLOW, DEFAULT);

    // parse server's response's header
    struct responseAttributes serverResponseAttributes = parseResponseHeader(receiveBuffer);

    printResponseAttributes(&serverResponseAttributes);


    if (serverResponseAttributes.contentLength == 0 && serverResponseAttributes.isChunked == 0)
      server_response_has_no_body = 1;

    // 200 case
    if (serverResponseAttributes.statusCode == 200)
    {
      // If the file type needs caching, then cache it
      if (clientRequestAttributes.typeNeedsCaching)
      {
        if (cacheServerResponse(receiveBuffer, clientRequestAttributes.URL, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%scache Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }
      // Else, simply forward the response
      else
      {
        if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%sforward Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }

      printf("%sok here?2%s\n", FG_RED, DEFAULT);
    }
    // 304 case
    else if (serverResponseAttributes.statusCode == 304)
    {
      if (is_case_4)
      {
        if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
        {
          printf("%srespond Error%s\n", BG_RED, DEFAULT);
          break;
        }
        goto forwardBackComplete;
      }
      else
      {
        if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%sforward Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }
    }
    // Status code is otherwise case
    else
    {
      if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
      {
        printf("%sforward Error%s\n", BG_RED, DEFAULT);
        break;
      }
    }


    forwardBackComplete:
    oneLoopisDone:

    if (serverResponseAttributes.serverClose)
    {
      printf("%sThe server's response has Connection: close. Close server_sd now. %s\n", BG_PURPLE, DEFAULT);
      server_sd_reusable = 0;
      close(server_sd);
    }

    // This part is a workaround for the mysterious phenomenon
    // that the server_sd, after a c->p->s->p->c loop, cannot be reused
    // even though server did not respond "Connection: close" or likewise
    // Here call recv() once to test if server closed the connection at its side
    // if server did, close the server_sd
    char testByte;
    bytesReceived = recv(server_sd, &testByte, 1, MSG_PEEK | MSG_DONTWAIT);
    if (bytesReceived == 0)
    {
      printf("%sThe server silently closed the Connection. Close server_sd now. %s\n", BG_PURPLE, DEFAULT);
      server_sd_reusable = 0;
      close(server_sd);
    }

    if (server_response_has_no_body)
      break;

    if (clientRequestAttributes.clientClose)
      break;

    printf("%sOne Loop(c->p->s->p->c) is done.%s\n", BG_PURPLE, DEFAULT);

  }
  close(server_sd);
  close(client_sd);

  pthread_exit(0);
}