//====================================================== file = weblite.c ===== //= A super light weight HTTP server = //============================================================================= //= Notes: = //= 1) Compiles for Winsock only since uses Windows threads. Generates = //= one warning about unreachable code in main. Ignore this warning. = //= 2) Serves HTML and GIF only. = //= 3) Sometimes the browser drops a connection when doing a refresh. = //= This is handled by checking the recv() return code in the function = //= that handles GETs. = //= 4) The 404 HTML message does not always display in Explorer. = //=---------------------------------------------------------------------------= //= Execution notes: = //= 1) Execute this program in the directory which will be the root for = //= all file references (i.e., the directory that is considered at = //= "public.html"). = //= 2) Open a Web browser and surf to http://xxx.xxx.xxx.xxx/yyy where = //= xxx.xxx.xxx.xxx is the IP address or hostname of the machine that = //= weblite is executing on and yyy is the requested object. = //= 3) The only output (to stdout) from weblite is a message with the = //= of the file currently being sent = //=---------------------------------------------------------------------------= //= Build: bcc32 weblite.c, cl weblite.c wsock32.lib (or ws2_32.lib) = //= gcc weblite.c -lsocket -lnsl for BSD = //=---------------------------------------------------------------------------= //= Execute: weblite = //=---------------------------------------------------------------------------= //= History: KJC (12/29/00) - Genesis (from server.c) = //= HF (01/25/01) - Ported to multi-platform environment = //============================================================================= #define UNIX // WIN for Windows environment, UNIX for BSD or LINUX env. //----- Include files --------------------------------------------------------- #include // Needed for printf() #include // Needed for exit() #include // Needed for strcpy() and strlen() #include // Needed for file i/o constants #include // Needed for file i/o constants #include /* FOR BSD UNIX/LINUX ---------------------------------------------------- */ #ifdef UNIX #include // #include // #include // #include // #include #endif /* ------------------------------------------------------------------------ */ /* FOR WIN ---------------------------------------------------------------- */ #ifdef WIN #include // Needed for _threadid #include // Needed for _beginthread() and _endthread() #include // Needed for open(), close(), and eof() #include #include // Needed for all Winsock stuff // Lazy struct fixes typedef int32_t socklen_t; #endif /* ------------------------------------------------------------------------ */ //----- HTTP response messages ---------------------------------------------- #define OK_IMAGE "HTTP/1.0 200 OK\nContent-Type:image/gif\n\n" #define OK_TEXT "HTTP/1.0 200 OK\nContent-Type:text/html\n\n" #define NOTOK_404 "HTTP/1.0 404 Not Found\nContent-Type:text/html\n\n" #define MESS_404 "

FILE NOT FOUND

" //----- Defines ------------------------------------------------------------- #define BUF_SIZE 4096 // Buffer size (big enough for a GET) #define PORT_NUM 7080 // Port number for a Web server //----- Function prototypes ------------------------------------------------- void ClientRequest(int client_s); //===== modeule main ======================================================== int main(void) { /* FOR WIN ------------------------------------------------------------- */ #ifdef WIN WORD wVersionRequested = MAKEWORD(1, 1); // Stuff for WSA functions WSADATA wsaData; // Stuff for WSA functions #endif /* --------------------------------------------------------------------- */ unsigned int server_s; // Server socket descriptor struct sockaddr_in server_addr; // Server Internet address unsigned int client_s; // Client socket descriptor struct sockaddr_in client_addr; // Client Internet address struct in_addr client_ip_addr; // Client IP address socklen_t addr_len; // Internet address length /* FOR UNIX/LINUX ------------------------------------------------------ */ #ifdef UNIX int nChild_proc_id; // New child process ID. #endif /* --------------------------------------------------------------------- */ /* FOR WIN ------------------------------------------------------------- */ #ifdef WIN // Initialize winsock WSAStartup(wVersionRequested, &wsaData); #endif /* --------------------------------------------------------------------- */ // Create a socket, fill-in address information, and then bind it server_s = socket(AF_INET, SOCK_STREAM, 0); if (server_s == -1) { printf("ERROR - Unable to create socket on server\n"); exit(1); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_NUM); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); int bindRet = bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (bindRet == -1) { printf("ERROR - Unable to bind socket\n"); exit(1); } // Listen for connections and then accept listen(server_s, 100); // Main loop to listen, accept, and then spin-off a thread to handle the GET while (1) { addr_len = sizeof(client_addr); client_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len); if (client_s == -1) { perror("ERROR - Unable to create socket to client\n"); continue; } std::async(std::launch::async, ClientRequest, client_s); } close(server_s); return (1); } void ClientRequest(int client_s) { char in_buf[BUF_SIZE]; // Input buffer for GET resquest char out_buf[BUF_SIZE]; // Output buffer for HTML response char *file_name; // File name unsigned int fh; // File handle unsigned int buf_len; // Buffer length for file reads unsigned int retcode; // Return code // Receive the GET request from the Web browser retcode = recv(client_s, in_buf, BUF_SIZE, 0); // Handle the GET if there is one (see note #3 in the header) if (retcode != -1) { // Parse out the filename from the GET request strtok(in_buf, " "); file_name = strtok(NULL, " "); // Open the requested file // - Start at 2nd char to get rid of leading "\" #ifdef WIN fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); #endif #ifdef UNIX fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE); #endif // Generate and send the response (404 if could not open the file) if (fh == -1) { printf("File %s not found - sending an HTTP 404 \n", &file_name[1]); strcpy(out_buf, NOTOK_404); send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, MESS_404); send(client_s, out_buf, strlen(out_buf), 0); } else { printf("File %s is being sent \n", &file_name[1]); if (strstr(file_name, ".gif") != NULL) strcpy(out_buf, OK_IMAGE); else strcpy(out_buf, OK_TEXT); send(client_s, out_buf, strlen(out_buf), 0); do { buf_len = read(fh, out_buf, BUF_SIZE); send(client_s, out_buf, buf_len, 0); } while (buf_len != 0); close(fh); } } // Close the client socket and end the thread close(client_s); }