Question
Build TCP server in cdont know how to implement the last 7 small parts question marks /* http_server.c - http 1.0 server */ #include #include
Build TCP server in cdont know how to implement the last 7 small parts question marks
/* http_server.c - http 1.0 server */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "helpers.h"
/*------------------------------------------------------------------------
* Program: http server
*
* Purpose: allocate a socket and then repeatedly execute the following:
* (1) wait for the next connection from a client
* (2) read http request, reply to http request
* (3) close the connection
* (4) go back to step (1)
*
* Syntax: http_server [ port ]
*
* port - protocol port number to use
*
* Note: The port argument is optional. If no port is specified,
* the server uses the port specified in config.h
*
*------------------------------------------------------------------------
*/
int main(int argc, char *argv[])
{
struct sockaddr_in serv_addr , client_addr; /* structure to hold server's address */
int listen_socket, connection_socket;
int port;
pid_t pid; /* id of child process to handle request */
char response_buffer[MAX_HTTP_RESP_SIZE];
int status_code;
char * status_phrase;
/* 1) Create a socket */
listen_socket = socket(AF_INET,SOCK_STREAM,0);
/* Check command-line argument for port and extract */
/* port number if one is specified. Otherwise, use default */
if (argc > 1) { /* if argument specified */
port = atoi(argv[1]); /* convert from string to integer */
} else {
port = DEFAULT_PORT;
}
if (port <= 0) { /* test for legal value */
fprintf(stderr, "bad port number %d", port);
exit(EXIT_FAILURE);
}
/* 2) Set the values for the server address structure: serv_addr */
memset(&serv_addr,0,sizeof(serv_addr)); /* clear sockaddr structure */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(6789);
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
/* 3) Bind the socket to the address information set in serv_addr */
bind(listen_socket,(struct sockaddr *)&serv_addr , sizeof(serv_addr));
/* 4) Start listening for connections */
listen(listen_socket, 128);
/* Main server loop - accept and handle requests */
while (true) {
/* 5) Accept a connection */
socklen_t client_len=sizeof(client_addr);
connection_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &client_len);
/* Fork a child process to handle this request */
if ((pid = fork()) == 0) {
/*----------START OF CHILD CODE----------------*/
/* we are now in the child process */
/* child does not need access to listen_socket */
if ( close(listen_socket) < 0) {
fprintf(stderr, "child couldn't close listen socket");
exit(EXIT_FAILURE);
}
struct http_request new_request; // defined in httpreq.h
/* 6) call helper function to read the request *
* this will fill in the struct new_request for you *
* see helper.h and httpreq.h
Once we have closed the listen_socket in the child process, we create an http_request structure which will be used to store the information about the HTTP request, such as it's method, and URI and pass this structure to the helper function Parse_HTTP_Request( ). This helper will read the request from the given socket and fill in thehttp_request structure for you. The interface information about the helper functions is in the file helpers.h You do not need to understand the code in the helper functions, but if you want to have a look, the file helpers.c contains the implementation. new_request will now be filled with the method and URI that the client sent. Note that if the request is not properly formed, Parse_HTTP_Request( ) will return false. */
/*** PART A: PRINT OUT
* URI, METHOD and return value of Parse_HTTP_Request()
*/
/**** PART B ONLY *******/
/* 7) Decide which status_code and reason phrase to return to client */
/*You now need to write code that will decide, based on the results fromParse_HTTP_Request(), what the status_code and status_phrase variables should be set to for the response. Your server is required to handle and return the correct status code and phrase for the following situations:
The requested resource is available
The requested resource does not exist
The requested method isn't implemented (your server will only implement GET and HEAD methods)
The client sent an invalid request */
????????????????????????????????????
// set the reply to send
/* Having determined the appropriate response, we can now send the response header. Check the HTTP response format to make sure you fill this in correctly! */
sprintf(response_buffer, "HTTP/1.0 %d %s ", ????FILL IN????,????FILL IN????);
/* Now we can send the status line and our header lines to the browser by writing to the socket. Be sure you send to the correct socket. */
printf("Sending response line: %s ", response_buffer);
send(?????fill in?????,response_buffer,strlen(response_buffer),0);
/* Now that the status line has been placed on the socket on its way to the browser, it is time to do the same with the response headers and entity body. We need to decide whether or not an entity body should be returned. You will need to understand the difference between GET and HEAD. We can use the helper Is_Valid_Resource() to see if the requested file exists. If the requested file does exist, we can call helper function Send_Resource() to send the Content-Length header and the file contents on the socket (see helpers.h for how to use Is_Valid_Resource()and Send_Resource() ). */
// send resource if requested, under what condition will the server send an
// entity body?
if (????FILL IN CONDITION????)
Send_Resource(connection_socket, new_request.URI);
else {
// don't need to send resource. end HTTP headers
send(????FILL IN SOCKET????, " ", strlen(" "), 0);
}
/***** END PART B ****/
/* child's work is done, close remaining descriptors and exit */
if ( close(connection_socket) < 0) {
fprintf(stderr, "closing connected socket failed");
exit(EXIT_FAILURE);
}
/* all done return to parent */
exit(EXIT_SUCCESS);
}
/*----------END OF CHILD CODE----------------*/
/* back in parent process */
/* close parent's reference to connection socket, */
/* then back to top of loop waiting for next request */
if ( close(connection_socket) < 0) {
fprintf(stderr, "closing connected socket failed");
exit(EXIT_FAILURE);
}
/* if child exited, wait for resources to be released */
waitpid(-1, NULL, WNOHANG);
} // end while(true)
}
_________________________________________________________________--
Helpers.c (resource need to look at)
/*----------------------------------------------------------
* Function: Parse_HTTP_Request
*
* Purpose: Reads HTTP request from a socket and fills in a data structure
* (see httpreq.h with the request values (method and URI)
*
* Parameters: socket : the socket to read the request from
* request_value : address of struct to write the values to
*
* Returns: true if successfull, false if request is not a valid HTTP request
*
*-----------------------------------------------------------
*/
#include
bool Parse_HTTP_Request(int socket, struct http_request * request_values) {
char buffer[MAX_HTTP_REQ_SIZE];
char request[MAX_HTTP_REQ_SIZE];
ssize_t recvdBytes;
// read request
request[0] = '\0';
do {
recvdBytes = recv(socket, buffer, sizeof(buffer), 0);
if (recvdBytes > 0) {
strncat(request, buffer, recvdBytes);
}
} while (recvdBytes > 0 && (strstr(request, " ") == NULL));
printf("received request: %s ", request);
// parse request
char *line, *method;
char *line_ptr;
line = strtok_r(request, " ", &line_ptr);
method = strtok(line, " ");
request_values->method = malloc (strlen(method) + 1);
printf("Method is: %s ", method);
if (method == NULL)
return false;
strcpy(request_values->method, method);
// parse the requested URI
char * request_URI = strtok(NULL, " ");
printf("URI is: %s ", request_URI);
if (request_URI == NULL)
return false;
request_values->URI = malloc (strlen(request_URI)+1);
strcpy(request_values->URI, request_URI);
char * version = strtok(NULL, " ");
if (version == NULL)
return false;
printf("version is: %s ", version);
// we can ignore headers, so just check that the blank line exists
if ((strstr(request, " ") == NULL))
return true;
else
return false;
}
/*----------------------------------------------------------
* Function: Is_Valid_Resource
*
* Purpose: Checks if URI is a valid resource
*
* Parameters: URI : the URI of the requested resource, both absolute
* and relative URIs are accepted
*
* Returns: false : the URI does not refer to a resource on the server
* true : the URI is available on the server
*
*-----------------------------------------------------------
*/
bool Is_Valid_Resource(char * URI) {
char * server_directory, * location;
char * resource;
/* set the root server directory */
if ( (server_directory = (char *) malloc(PATH_MAX)) != NULL)
getcwd(server_directory, PATH_MAX);
/* remove http://domain/ from URI */
resource = strstr(URI, "http://");
if (resource == NULL) {
/* no http:// check if first character is /, if not add it */
if (URI[0] != '/')
resource = strcat("/", URI);
else
resource = URI;
}
else
/* if http:// resource must start with '/' */
resource = strchr(resource, '/');
if (resource == NULL)
/* invalid resource format */
return false;
/* append root server directory *
* for example if request is for /images/myphoto.jpg *
* and directory for server resources is /var/www/ *
* then the resource location is /var/www/images/myphoto.jpg */
strcat(server_directory, RESOURCE_PATH);
location = strcat(server_directory, resource);
printf("server resource location: %s ", location);
/* check file access */
if (!(access(location, R_OK))) {
puts("access OK ");
free(server_directory);
return true;
} else {
puts("access failed ");
free(server_directory);
return false;
}
}
/*----------------------------------------------------------
* Function: Send_Resource
*
* Purpose: Sends the contents of the file referred to in URI on the socket
*
* Parameters: socket : the socket to send the content on
* URI : the Universal Resource Locator, both absolute and
* relative URIs are accepted
*
* Returns: void - errors will cause exit with error printed to stderr
*
*-----------------------------------------------------------
*/
void Send_Resource(int socket, char * URI) {
char * server_directory, * resource;
char * location;
/* set the root server directory */
if ( (server_directory = (char *) malloc(PATH_MAX)) != NULL)
getcwd(server_directory, PATH_MAX);
/* remove http://domain/ from URI */
resource = strstr(URI, "http://");
if (resource == NULL) {
/* no http:// check if first character is /, if not add it */
if (URI[0] != '/')
resource = strcat("/", URI);
else
resource = URI;
}
else
/* if http:// resource must start with '/' */
resource = strchr(resource, '/');
/* append root server directory *
* for example if request is for /images/myphoto.jpg *
* and directory for server resources is /var/www/ *
* then the resource location is /var/www/images/myphoto.jpg */
strcat(server_directory, RESOURCE_PATH);
location = strcat(server_directory, resource);
/* open file and send contents on socket */
FILE * file = fopen(location, "r");
if (file < 0) {
fprintf(stderr, "Error opening file. ");
exit(EXIT_FAILURE);
}
char c;
long sz;
char content_header[MAX_HEADER_LENGTH];
/* get size of file for content_length header */
fseek(file, 0L, SEEK_END);
sz = ftell(file);
rewind(file);
sprintf(content_header, "Content-Length: %ld ", sz);
printf("Sending headers: %s ", content_header);
send(socket, content_header, strlen(content_header), 0);
printf("Sending file contents of %s ", location);
free(server_directory);
while ( (c = fgetc(file)) != EOF ) {
if ( send(socket, &c, 1, 0) < 1 ) {
fprintf(stderr, "Error sending file.");
exit(EXIT_FAILURE);
}
printf("%c", c);
}
puts(" finished reading file ");
fclose(file);
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started