#include #include #include #include #include #include // basic include files #include // to parse and sed #include // to include date of response message #include // to Create threads #include // here #include // #include // #include // for socket communications #include "http.h" // Macro constant defined. response status & size of data, etc. int th_num = 0; int rq_num = 0; int main(int argc, char *argv[]) { pthread_t i_thread; // thread id struct sockaddr_in clientaddr, serveraddr; // addrress struct char thread_data[M_DATA]; // thread's arguments int server_sockfd, client_sockfd, client_len; // socket fd & address struct's length memset(thread_data, 0x00, M_DATA); if (argc != 2) { printf("Usage : http [port number]\n"); exit(0); } if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Server Socket created error "); } // Create Socket bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(atoi(argv[1])); // initialize address struct. if (bind(server_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1) { perror("Server Socket bind failed "); // bind socket fd & addrress. } if (listen(server_sockfd, 5) == -1) { perror("listen error "); // Listen } while (1) { client_len = sizeof(clientaddr); client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr, (socklen_t *)&client_len); // Wait client's connection. memcpy(thread_data, (void *)&client_sockfd, sizeof(client_sockfd)); memcpy(thread_data + sizeof(client_sockfd), (void *)&clientaddr, client_len); if (pthread_create(&i_thread, NULL, client, (void *)thread_data) == -1) { perror("Thread create error "); } // create thread for client's request. else { printf(">> Thread [%u] create success!! num : %d \n", (unsigned int)i_thread, ++th_num); } } // return waiting status. } void *client(void *data) { int client_sockfd; struct sockaddr_in clientaddr; int client_len; char buf[BUFSIZ]; pthread_t ithread; ithread = pthread_self(); pthread_detach(ithread); client_len = sizeof(clientaddr); memcpy((void *)&client_sockfd, (char *)data, sizeof(int)); memcpy((void *)&clientaddr, (char *)data + sizeof(int), client_len); memset(buf, 0x00, BUFSIZ); // parsing argument. if (read(client_sockfd, buf, BUFSIZ) <= 0) { // read request. close(client_sockfd); pthread_exit((void *)NULL); } else { printf("\nThread [%u] : Client Request rq_num : %d \n", (unsigned int)ithread , ++rq_num); printf("---------------------------------------\n"); printf("%s", buf); printf("---------------------------------------\n\n"); request_response(buf, client_sockfd); // process request. } close(client_sockfd); // dissconnect. pthread_exit((void *)NULL); // destroy thread. } void request_response(char *buf, int client_sockfd) { char response_header[M_DATA]; char method[M_METHOD]; int result = -1; int fd = -1; result = Parser(buf, response_header, &fd, method); // parses request write(client_sockfd, response_header, strlen(response_header)); write(client_sockfd, "\r\n", 2); // sends header. memset(buf, 0x00, BUFSIZ); if (result == OK) { if (strncmp(method, "GET", 3) == 0) { while (read(fd, buf, BUFSIZ) > 0) { write(client_sockfd, buf, BUFSIZ); } // if OK, it sends data. } else if (strncmp(method, "POST", 4) == 0) { } else if (strncmp(method, "HEAD", 4) == 0) { } // yet, this part doesn't be implemented. } } int Parser(char *request, char *response_header, int *fd, char *method) { char *tokenizer[10] = {"\r\n", " ", "\0"}; char error_str[40]; char *url; char version[15]; char c_type[15] = "Unknown"; long c_size = 0; char header[BUFSIZ]; // for parsing. int token_index = 0, index = 0; int result = OK; url = (char *)malloc(M_URL); while (*tokenizer[1] != *request) { // White space is tokenizer. method[token_index++] = *request++; if (token_index >= M_METHOD) { result = FAULT_METHOD; break; } } if (result == FAULT_METHOD || (strncmp(method, "GET", 3) && strncmp(method, "POST", 4) && strncmp(method, "HEAD", 4))) { result = FAULT_METHOD; sprintf(error_str, "%s %d Bad Request\r\n", SERVER_VERSION, result); strcpy(response_header, error_str); make_DefaultHeader(&response_header[strlen(error_str)], result); return result; } token_index = 0; request++; // Skip white space. while (*tokenizer[1] != *request) { // White space is tokenizer. url[token_index++] = *request++; if (token_index >= M_URL) { result = FAULT_URL; sprintf(error_str, "%s %d Not Found\r\n", SERVER_VERSION, result); break; } } if (result != FAULT_URL) { if (*url == '/') url++; if ((*fd = open(url, O_RDONLY)) < 0) { result = FAULT_URL; sprintf(error_str, "%s %d Not Found\r\n", SERVER_VERSION, result); } else { c_size = lseek(*fd, 0, SEEK_END); lseek(*fd, 0, SEEK_SET); // file size checking. index = strlen(url) - 1; while (url[index] != '.') { if (index-- == 0) { strcpy(c_type, "Unknown"); break; } } if (index != 0) { url = url + ++index; if (strncmp(url, "htm", 3) == 0 || strncmp(url, "html", 4) == 0) { strcpy(c_type, "text/html"); } else if (strncmp(url, "gif", 3) == 0) { strcpy(c_type, "image/gif"); } else if (strncmp(url, "bmp", 3) == 0) { strcpy(c_type, "image/bmp"); } else if (strncmp(url, "jpg", 3) == 0 || strncmp(url, "jpeg", 4) == 0) { strcpy(c_type, "image/JPEG"); } // if need, you can insert any type of file, above. } } index = token_index = 0; request++; // skip white space. } else { strcpy(response_header, error_str); make_DefaultHeader(&response_header[strlen(error_str)], result); return result; } while (*tokenizer[0] != *request && *(tokenizer[0] + 1) != *(request + 1)) { version[token_index++] = *request++; if (token_index >= 15) { result = BAD_VERSION; sprintf(error_str, "%s %d HTTP Version Not Supported\r\n", SERVER_VERSION, result); break; } } if (result == OK) { sprintf(error_str, "%s %d OK\r\n", SERVER_VERSION, result); strcpy(response_header, error_str); make_DefaultHeader(&response_header[strlen(error_str)], result); sprintf(response_header, "%sContent-Length: %ld\r\n", response_header, c_size); sprintf(response_header, "%sContent-Type: %s\r\n", response_header, c_type); strcpy(header, request); } else { strcpy(response_header, error_str); make_DefaultHeader(&response_header[strlen(error_str)], result); } return result; } void make_DefaultHeader(char *Default_header, int result) { struct timeval tv; char date[30]; int index = 0; gettimeofday(&tv, NULL); strcpy(date, ctime(&(tv.tv_sec))); while (date[index] != '\n') index++; strcpy(&date[index], "\r\n"); // date\n -> date\r\n sprintf(Default_header, "Connection close\r\nDate: %sServer: Apache/1.3.0 (Unix)\r\nLast-Modified: %s", date, date); // Last modified is current. if (result != OK) { strcat(Default_header, "Content-Length: 0\r\n"); strcat(Default_header, "Content-Type: Unknown\r\n"); // Fault request has no content. } } // end of program