2023-09-30 02:36:18 -05:00
|
|
|
//====================================================== 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 =
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
//----- Include files ---------------------------------------------------------
|
|
|
|
#include <string.h> // Needed for strcpy() and strlen()
|
|
|
|
#include <fcntl.h> // Needed for file i/o constants
|
|
|
|
#include <sys/stat.h> // Needed for file i/o constants
|
2023-09-30 04:08:29 -05:00
|
|
|
#include <future>
|
2023-10-02 16:47:48 -05:00
|
|
|
#include <iostream>
|
|
|
|
#include <vector>
|
|
|
|
#include "network.hpp"
|
2023-09-30 02:36:18 -05:00
|
|
|
|
|
|
|
/* FOR BSD UNIX/LINUX ---------------------------------------------------- */
|
|
|
|
#ifdef UNIX
|
|
|
|
#include <sys/types.h> //
|
|
|
|
#include <netinet/in.h> //
|
|
|
|
#include <sys/socket.h> //
|
|
|
|
#include <arpa/inet.h> //
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
|
|
|
/* FOR WIN ---------------------------------------------------------------- */
|
|
|
|
#ifdef WIN
|
|
|
|
#include <io.h> // Needed for open(), close(), and eof()
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
|
2023-09-30 04:08:29 -05:00
|
|
|
|
2023-09-30 02:36:18 -05:00
|
|
|
//----- 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 "<html><body><h1>FILE NOT FOUND</h1></body></html>"
|
|
|
|
|
|
|
|
//----- Defines -------------------------------------------------------------
|
|
|
|
#define BUF_SIZE 4096 // Buffer size (big enough for a GET)
|
|
|
|
#define PORT_NUM 7080 // Port number for a Web server
|
|
|
|
|
|
|
|
//----- Function prototypes -------------------------------------------------
|
2023-09-30 17:10:42 -05:00
|
|
|
void ClientRequest(int client_s);
|
2023-09-30 02:36:18 -05:00
|
|
|
|
|
|
|
//===== modeule main ========================================================
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
/* FOR WIN ------------------------------------------------------------- */
|
|
|
|
#ifdef WIN
|
|
|
|
WORD wVersionRequested = MAKEWORD(1, 1); // Stuff for WSA functions
|
|
|
|
WSADATA wsaData; // Stuff for WSA functions
|
2023-10-04 01:10:24 -05:00
|
|
|
WSAStartup(wVersionRequested, &wsaData);
|
2023-09-30 02:36:18 -05:00
|
|
|
#endif
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
2023-10-02 16:47:48 -05:00
|
|
|
std::vector<std::future<void>> pending_futures;
|
|
|
|
Server webserver(kWebserverPort);
|
|
|
|
Client proxy;
|
2023-09-30 02:36:18 -05:00
|
|
|
|
|
|
|
// Main loop to listen, accept, and then spin-off a thread to handle the GET
|
|
|
|
while (1)
|
|
|
|
{
|
2023-10-02 16:47:48 -05:00
|
|
|
if (proxy.ConnectFrom(webserver.socketFD) != 0)
|
|
|
|
{
|
|
|
|
std::cerr << "ERROR - Unable to create socket to client" << std::endl;
|
2023-09-30 04:08:29 -05:00
|
|
|
continue;
|
2023-10-02 16:47:48 -05:00
|
|
|
}
|
|
|
|
auto newThreadRequest = std::async(std::launch::async, ClientRequest, proxy.socketFD);
|
|
|
|
pending_futures.push_back(std::move(newThreadRequest));
|
2023-09-30 17:10:42 -05:00
|
|
|
}
|
2023-10-02 16:47:48 -05:00
|
|
|
webserver.Close();
|
|
|
|
return 0;
|
2023-09-30 02:36:18 -05:00
|
|
|
}
|
|
|
|
|
2023-09-30 17:10:42 -05:00
|
|
|
void ClientRequest(int client_s) {
|
2023-09-30 04:08:29 -05:00
|
|
|
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);
|
|
|
|
|
2023-10-03 18:34:21 -05:00
|
|
|
if (retcode == -1) { std::cerr << "ERROR (info) - recv" << std::endl; }
|
2023-10-03 23:06:11 -05:00
|
|
|
if (retcode == 0) {
|
|
|
|
std::cout << "LOG (info) - Webserver received no data" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
2023-09-30 04:08:29 -05:00
|
|
|
// Handle the GET if there is one (see note #3 in the header)
|
2023-10-03 18:34:21 -05:00
|
|
|
// Parse out the filename from the GET request
|
|
|
|
strtok(in_buf, " ");
|
|
|
|
file_name = strtok(NULL, " ");
|
2023-09-30 04:08:29 -05:00
|
|
|
|
2023-10-03 18:34:21 -05:00
|
|
|
// Open the requested file
|
|
|
|
// - Start at 2nd char to get rid of leading "\"
|
2023-09-30 04:08:29 -05:00
|
|
|
#ifdef WIN
|
2023-10-03 18:34:21 -05:00
|
|
|
fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
|
2023-09-30 04:08:29 -05:00
|
|
|
#endif
|
|
|
|
#ifdef UNIX
|
2023-10-03 18:34:21 -05:00
|
|
|
fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE);
|
2023-09-30 04:08:29 -05:00
|
|
|
#endif
|
|
|
|
|
2023-10-03 18:34:21 -05:00
|
|
|
// 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);
|
2023-10-03 22:03:21 -05:00
|
|
|
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';
|
2023-10-03 18:34:21 -05:00
|
|
|
} while (buf_len == BUF_SIZE);
|
2023-10-03 22:03:21 -05:00
|
|
|
std::cout << std::endl;
|
2023-10-04 01:10:24 -05:00
|
|
|
#ifdef WIN
|
|
|
|
closesocket(fh);
|
|
|
|
#endif
|
|
|
|
#ifdef UNIX
|
2023-10-03 18:34:21 -05:00
|
|
|
close(fh);
|
2023-10-04 01:10:24 -05:00
|
|
|
#endif
|
2023-10-03 18:34:21 -05:00
|
|
|
}
|
2023-09-30 04:08:29 -05:00
|
|
|
// Close the client socket and end the thread
|
2023-10-04 01:10:24 -05:00
|
|
|
#ifdef WIN
|
|
|
|
closesocket(client_s);
|
|
|
|
#endif
|
|
|
|
#ifdef UNIX
|
2023-09-30 04:08:29 -05:00
|
|
|
close(client_s);
|
2023-10-04 01:10:24 -05:00
|
|
|
#endif
|
2023-09-30 04:08:29 -05:00
|
|
|
}
|
|
|
|
|