//====================================================== 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 strcpy() and strlen() #include // Needed for file i/o constants #include // Needed for file i/o constants #include #include #include #include "network.hpp" /* 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 /* --------------------------------------------------------------------- */ std::vector> pending_futures; Server webserver(kWebserverPort); Client proxy; /* FOR WIN ------------------------------------------------------------- */ #ifdef WIN // Initialize winsock WSAStartup(wVersionRequested, &wsaData); #endif /* --------------------------------------------------------------------- */ // Main loop to listen, accept, and then spin-off a thread to handle the GET while (1) { if (proxy.ConnectFrom(webserver.socketFD) != 0) { std::cerr << "ERROR - Unable to create socket to client" << std::endl; continue; } auto newThreadRequest = std::async(std::launch::async, ClientRequest, proxy.socketFD); pending_futures.push_back(std::move(newThreadRequest)); } webserver.Close(); return 0; } 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); if (retcode == -1) { std::cerr << "ERROR (info) - recv" << std::endl; } if (retcode == 0) { std::cout << "LOG (info) - Webserver received no data" << std::endl; return; } // Handle the GET if there is one (see note #3 in the header) // 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); buf_len = send(client_s, out_buf, buf_len, 0); if (buf_len == -1) { std::cerr << "ERROR (info) - send -1\n"; std::cerr << "File causing error: " << &file_name[1] << '\n'; std::cerr << "Errno: " << errno << '\n'; std::cout << std::endl; return; } std::cout << "LOG (info) - webserver send size: " << buf_len << '\n'; } while (buf_len == BUF_SIZE); std::cout << std::endl; close(fh); } // Close the client socket and end the thread close(client_s); }