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); }