Code:
if (strstr (request_dat.method, "GET"))
{
FILE *infile;
long len;
char *file_dat;
infile = fopen (request_dat.filepath, "rb");
if (!infile)
{
cout << " File Error! ";
cout << SendHTTPError (NOT_FOUND, client_socket);
closesocket (client_socket);
return;
}
fseek(infile,0,SEEK_END);
len = ftell(infile);
fseek(infile,0,SEEK_SET);
file_dat = new char [len];
fread (file_dat,sizeof (int),len,infile);
fclose (infile);
strcpy (response, "HTTP/1.0 200 OK\r\n");
strncat (response, "Content-Type: ", MAX_BUFFER);
strncat (response, content_types[getMimeType(request_dat.filepath)].mime, MAX_BUFFER);
sprintf (response+strlen(response), "\r\nContent-Length: %ld\r\n", len);
strncat (response, "\r\n", MAX_BUFFER);
cout << response << endl;
send (client_socket, response, strlen (response), 0);
send (client_socket, file_dat, len, 0);
delete [] file_dat;
closesocket (client_socket);
}
Here is the entire source code:
Code:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* server.cpp: A simple web server made to run on the windows platform. This server *
* was designed for Hilltop Baptist Church as a means to run their web page. The web *
* server was designed as a project for me, and is free to anyone who would use or *
* modify it. Just make sure you credit me in your work if you use ideas or any part *
* of this web server in your code. By the way, I took alot of examples from *
* Stuart Patterson's web server Charlotte. And I mean, ALOT of examples!!! *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//first thing's first: include the header files
#include <windows.h>
#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
#include <process.h>
//define some constants
#define MAX_BUFFER 1024
#define SMALL_BUF 10
#define PARSE_SUCCESS 1
#define BAD_REQUEST_METHOD -1
#define PARSE_ERROR -2
#define ACCEPT_ERROR -4
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* the definitions of all the HTTP status codes that are or will be in future *
* versions supported by this software. These are the codes as defined by the *
* HTTP 1.1 standard *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//supported successful status codes, currently used marked //used
#define OK "200" //used
//redirection status codes in case of redirect, currently used marked //used
#define PERMANENT_MOVE "301"
#define FOUND_ELSEWHERE "302"
#define SEE_OTHER_URI "303"
#define TEMPORARY_REDIRECT "307"
//client status codes for request errors, currently used marked //used
#define BAD_REQUEST "400" //used
#define UNAUTHORIZED "401"
#define FORBIDDEN "403"
#define NOT_FOUND "404" //used
#define METHOD_NOT_ALLOWED "405"
#define GONE "410"
//server status codes for server errors, currently used marked //used
#define INTERNAL_ERROR "500" //used
#define NOT_IMPLEMENTED "501" //used
#define SERVICE_UNAVAILABLE "503"
#define BAD_HTTP_VER "505" //used
/* * * * * * * * * * * * * * * * * * * * * *
* create some structures for program data *
* * * * * * * * * * * * * * * * * * * * * */
//a structure to hold data on the connected client
struct ClientData
{
in_addr client_ip;
SOCKET client_socket;
};
//a structure to hold data on the client's request
struct RequestData
{
char method[SMALL_BUF];
char url[MAX_PATH];
char filepath[MAX_PATH];
char http_ver[SMALL_BUF];
};
//a structure to hold the Content-Types and their equivalent file extensions
struct MimeTypes
{
char *file_ext;
char *mime;
};
//a structure used to hold the settings for the server, will be constant values for now
struct Settings
{
char *serv_file_path;
char *default_file;
char *serv_err_path;
};
//a structure used to make a list of the http headers in the request
struct header_node
{
char *header_name;
char *header_value;
header_node *next;
};
//global variables
char *methods[] = { "GET", "HEAD" };
char *http_ver = "1.0 ";
Settings serv_settings = { "C:\\server", "\\index.html", "C:\\server\\errors\\" };
MimeTypes content_types[] = {{ ".txt" , "text/plain" },
{ ".html", "text/html" },
{ ".htm" , "text/html" },
{ ".gif" , "image/gif" },
{ ".jpg" , "image/jpeg" }};
//function prototypes. Those commented out not available as of yet
SOCKET establish (unsigned short); //done
int getMimeType (char *); //done
int socket_read (SOCKET, char *, int); //done
int ParseHTTPRequest (char *, RequestData&); //done
void handle_client (void *); //done
int SendHTTPError (char *, SOCKET); //done
char *string_cat (char *, char *); //done
//main function
int main ()
{
int client_addr_len;
WSADATA wsaDat;
SOCKET servSocket;
struct sockaddr_in client_address;
ClientData *client_dat;
if (WSAStartup (MAKELONG (1,1), &wsaDat) == SOCKET_ERROR)
{
cout << "Problem with WSAStartup";
exit (1);
}
servSocket = establish (80);
if (servSocket == INVALID_SOCKET)
{
perror ("establish");
system ("pause");
exit (1);
}
for (;;)
{
SOCKET new_socket = accept (servSocket, (struct sockaddr *) &client_address, &client_addr_len);
if (new_socket == INVALID_SOCKET)
{
cout << "Error waiting for new connection!!!";
system ("pause");
exit (1);
}
cout << "Got connection\n";
client_dat = new ClientData;
client_dat->client_socket = new_socket;
memcpy (&(client_dat->client_ip), &client_address.sin_addr.s_addr, 4);
cout << inet_ntoa (client_address.sin_addr);
_beginthread(handle_client, 0, (void *) client_dat);
}
return 0;
}
void handle_client (void *client_dat)
{
SOCKET client_socket;
int num_chars;
char http_req[MAX_BUFFER], response[MAX_BUFFER];
RequestData request_dat;
client_socket = ((ClientData *) client_dat)->client_socket;
free (client_dat);
num_chars = socket_read (client_socket, http_req, MAX_BUFFER);
cout << http_req;
if (num_chars == SOCKET_ERROR || num_chars == 0)
{
cout << "SOCKET READ ERROR " << num_chars;
SendHTTPError (INTERNAL_ERROR, client_socket);
closesocket (client_socket);
return;
}
http_req[num_chars] = NULL;
if (http_req == NULL)
{
SendHTTPError (INTERNAL_ERROR, client_socket);
closesocket (client_socket);
return;
}
if (ParseHTTPRequest (http_req, request_dat) == PARSE_ERROR)
{
cout << "Error";
SendHTTPError (BAD_REQUEST, client_socket);
closesocket (client_socket);
return;
}
if (strstr (request_dat.method, "GET"))
{
FILE *infile;
long len;
char *file_dat;
infile = fopen (request_dat.filepath, "rb");
if (!infile)
{
cout << " File Error! ";
cout << SendHTTPError (NOT_FOUND, client_socket);
closesocket (client_socket);
return;
}
fseek(infile,0,SEEK_END);
len = ftell(infile);
fseek(infile,0,SEEK_SET);
file_dat = new char [len];
fread (file_dat,sizeof (int),len,infile);
fclose (infile);
strcpy (response, "HTTP/1.0 200 OK\r\n");
strncat (response, "Content-Type: ", MAX_BUFFER);
strncat (response, content_types[getMimeType(request_dat.filepath)].mime, MAX_BUFFER);
sprintf (response+strlen(response), "\r\nContent-Length: %ld\r\n", len);
strncat (response, "\r\n", MAX_BUFFER);
cout << response << endl;
send (client_socket, response, strlen (response), 0);
send (client_socket, file_dat, len, 0);
delete [] file_dat;
closesocket (client_socket);
}
else
{
SendHTTPError (NOT_IMPLEMENTED, client_socket);
}
}
SOCKET establish (unsigned short portnum)
{
char computer_name[256];
SOCKET new_sock;
struct sockaddr_in sa;
struct hostent *hp;
memset (&sa, 0, sizeof (struct sockaddr_in));
gethostname (computer_name, sizeof (computer_name));
hp = gethostbyname (computer_name);
if (hp == NULL)
return INVALID_SOCKET;
sa.sin_family = hp->h_addrtype;
sa.sin_port = htons (portnum);
new_sock = socket (AF_INET, SOCK_STREAM, 0);
if (new_sock == INVALID_SOCKET)
return INVALID_SOCKET;
if (bind (new_sock, (struct sockaddr *) &sa, sizeof (struct sockaddr_in)) == SOCKET_ERROR)
{
closesocket (new_sock);
return INVALID_SOCKET;
}
if (listen (new_sock, 20) == SOCKET_ERROR)
{
closesocket (new_sock);
return INVALID_SOCKET;
}
cout << "Still ok at return";
return new_sock;
}
int getMimeType (char *requested_file)
{
char *pos;
int num_elements;
pos = strrchr (requested_file, '.');
if (pos)
{
num_elements = sizeof (content_types) / sizeof (MimeTypes);
for (int count = 0; count < num_elements; ++count)
{
if (stricmp (content_types[count].file_ext,pos) == 0)
return count;
}
}
return 0;
}
int socket_read(SOCKET client_socket, char *receivebuffer, int buffersize)
{
int size = 0, totalsize = 0;
do
{
size = recv(client_socket,receivebuffer+totalsize,buffersize-totalsize,0);
if ( size != 0 && size != SOCKET_ERROR )
{
totalsize += size;
// are we done reading the http header?
if ( strstr(receivebuffer,"\r\n\r\n") )
break;
}
else
totalsize = size; // remember error state for return
} while ( size != 0 && size != SOCKET_ERROR );
return(totalsize);
}
int ParseHTTPRequest (char *request, RequestData& request_data)
{
char *pos;
pos = (strtok (request, " "));
if (pos == NULL)
return PARSE_ERROR;
strncpy (request_data.method, pos, SMALL_BUF);
pos = strtok (NULL, " ");
if (pos == NULL)
return PARSE_ERROR;
strncpy (request_data.url, pos, SMALL_BUF);
pos = strtok (NULL, "\r");
if (pos == NULL)
return PARSE_ERROR;
strncpy (request_data.http_ver, pos, SMALL_BUF);
strcpy (request_data.filepath, serv_settings.serv_file_path);
if (strcmp(request_data.url, "\\"))
strcat (request_data.filepath, serv_settings.default_file);
else
strcat (request_data.filepath, request_data.url);
_fullpath (request_data.filepath, request_data.filepath, MAX_PATH);
return PARSE_SUCCESS;
}
int SendHTTPError (char *error, SOCKET to_send)
{
int length;
FILE *infile;
char std_err_file[MAX_PATH] = "", *contents, response[MAX_BUFFER];
strcat (std_err_file, serv_settings.serv_err_path);
strcat (std_err_file, error);
strcat (std_err_file, ".html");
strcpy (response, "HTTP/");
strcat (response, http_ver);
strcat (response, error);
strcat (response, "\r\n\r\n");
cout << response << endl;
cout << std_err_file << endl;
infile = fopen (std_err_file, "rb");
if (!infile)
{
return -1;
}
fseek (infile,0,SEEK_END);
length = ftell (infile);
fseek (infile,0, SEEK_SET);
contents = new char [length];
fread (contents, sizeof (char), length, infile);
fclose (infile);
send (to_send, response, strlen (response), 0);
send (to_send, contents, strlen (contents), 0);
return 0;
}
char *string_cat (char *string, char *to_add)
{
char *return_str;
return_str = (char *) malloc (strlen (string)+strlen(to_add)+1);
strcat (return_str, string);
strcat (return_str, to_add);
return return_str;
}
can anyone please please explain to me what i may be doing wrong for reading files? I've used this code in other programs and never had a problem before!