a ‘minimal’ web-server we can glean insights about the operation of the http protocol if we...
Post on 20-Dec-2015
217 views
TRANSCRIPT
A ‘minimal’ web-server
We can glean insights about the operation of the HTTP protocol if we create our own web-server
A web-browser is our ‘client’Mozilla Firefox Our ‘mini’ server
HTTP request line
Request ‘headers’
Optional ‘body’
Request-message (to server)
HTTP status line
Response ‘headers’
Optional ‘body’
Response-message (to client)
TCP server ‘boilerplate’
• By now we have seen that any connection oriented ‘server’ has some standard steps to execute by way of ‘connection-setup’– Initialize a host ‘socket-address’ structure– Create a TCP socket to use for ‘listening’– Bind the ‘socket-address’ to this socket– Enable the socket to ‘reuse’ its port-number– Convert the socket into a ‘listening’ socket– Accept a ‘connection-request’ from a client
‘helper’ functions
• We can employ standard library-functions to help setup the internet socket-address data-structure for our server’s host:– ‘gethostname()’– ‘gethostbyname()’– ‘inet_ntoa()’– ‘inet_addr()’– ‘htons()’
Our ‘sockaddr_in’ setup
padded with zeros sin_family sin_port sin_addr
struct sockaddr_in
Setup our ‘listening’ socket
‘iterative’ server-design
‘accept’ a connection-request from a client
‘receive’ the HTTP request-message
validate and process the HTTP command
‘send’ the HTTP response-message
‘close’ the connection with this client
We use some new ‘helper’ functions for these steps
‘fdopen()’
• To conveniently process the incoming stream of characters in a client’s HTTP request-message (which is organized into lines of text with CRLF as the line-delimiter), and to conveniently reply with similarly organized lines of text, we would like to use the standard ‘buffered’ i/o functions
• To do this requires substituting ‘streams’ for our TCP ‘connection’ socket, which is accomplished by using the ‘fdopen()’ library-function
‘fdopen()’ and ‘dup()’
• To conveniently process the incoming stream of characters in a client’s HTTP request-message (which is organized into lines of text with CRLF as the line-delimiter), and to conveniently reply with similarly organized lines of text, we would like to use the standard ‘buffered’ i/o functions
• To do this will require us to associate ‘streams’ with our TCP ‘connection’ socket, one for input, one for output, which we can accomplish using the ‘fdopen()’ and ‘dup()’ library-functions
Our i/o streams
• Our connection-socket is named ‘conn’:
• We associate an input-stream with ‘conn’:
• And we associate an output-stream with a ‘duplicate’ of our connection-socket ‘conn’:
struct sockaddr_in caddr = { 0 };socklen_t salen = sizeof( caddr );int conn = accept( sock, (sockaddr*)&caddr, &calen );
FILE *rx = fdopen( conn, “r” );
FILE *tx = fdopen( dup( conn ), “w” );
Request message’s lines
• Now it’s easy to receive the first ‘line’ of an HTTP request-message sent by our client:
• The remaining lines (request headers and the empty line) can be received like this:
char request[ BUFSIZ ] = { 0 };fgets( request, BUFSIZ, rx );
char header[ BUFSIZ ] = { 0 };while ( fgets( request, BUFSIZ, rx ) )
if ( strcmp( header, “\r\n” ) == 0 ) break;
Parsing the ‘request’
• The HTTP Request-line is comprised of three fields, separated by a blank-space and terminated with the CR/LF delimiter
• We can use the formatted string-scan function ‘sscanf()’ to parse the request
<COMMAND> <RESOURCE> <VERSION> ”\r\n”
char cmd[ BUFSIZ ] = { 0 }, arg[ BUFSIZ ] = { 0 };strcpy( arg, “./” ); // for restricting the client’s access
if ( sscanf( “%s%s”, cmd, arg+2 ) != 2 ) { perror( “sscanf” ); }
Validating the request
• For now our ‘miniature’ web-server only accepts the basic HTTP ‘GET’ command:
if ( strcmp( cmd, “GET” ) != 0 ) { // the HTTP Response status, headers, and empty linefprintf( tx, “HTTP/1.0 501 Not Implemented \r\n” );fprintf( tx, “Content-type: text/plain \r\n” );fprintf( tx, “\r\n” );
// the HTTP Response-message’s ‘body’fprintf( tx, “That one is not yet implemented \r\n”fclose( rx );fclose( tx );continue;}
‘nonexistent’ resource?
• The ‘stat()’ library-function can be used to verify that a requested resource exists
struct stat info = { 0 };if ( stat( arg, &info ) < 0 ) // the target does not exist
{// the HTTP Response’s status, headers, and empty linefprintf( tx, “HTTP/1.0 404 Not Found \r\n” );fprintf( tx, “Content-type: text/plain \r\n” );fprintf( tx, “\r\n” );
// the HTTP Response-message’s ‘body’fprintf( tx, “Requested item not found \r\n”fclose( rx );fclose( tx );continue;}
‘struct stat’
‘statdemo()’
• We have posted a demo-program which lets you see the information about a file which the Linux operating system keeps track of (including the ‘type’ of the file)
EXAMPLE: $ ./statdemo mywebsvr.cpp
‘folder’ or ‘file’?
• Our server can send its client a directory-listing if that type of resource is requested
if ( S_ISDIR( info.st_mode ) ) // the requested resource is a directory{// the HTTP Response’s status, headers, and empty linefprintf( tx, “HTTP/1.0 200 OK \r\n” );fprintf( tx, “Content-type: text/plain \r\n” );fprintf( tx, “\r\n” );
// the HTTP Response-message’s ‘body’fflush( tx );if ( fork() == 0 ) // child-process will deliver the directory-listing
{dup2( conn, 1 );dup2( conn, 2 );close( conn );execlp( “ls”, “ls”, “-l”, arg, NULL );exit( 1 );}
wait( NULL ); // parent-process will sleep until tge child exitsfclose( rx );fclose( tx );continue;}
A sample web-page
• We created a tiny webpage example for demonstrating our web-server’s ability to deliver an ‘HTML’ file to a web-browser
Delivering an ‘html’ file
if ( strcmp( strrchr( arg, ‘.’ ) + 1, “html” ) == 0 ) // the requested resource is an ‘html’ file{// the HTTP Response’s status, headers, and empty linefprintf( tx, “HTTP/1.0 200 OK \r\n” );fprintf( tx, “Content-type: text/html \r\n” );fprintf( tx, “\r\n” );
// the HTTP Response-message’s ‘body’fflush( tx );if ( fork() == 0 ) // child-process will deliver the file’s contents
{dup2( conn, 1 );dup2( conn, 2 );close( conn );execlp( “cat”, “cat”, arg, NULL );exit( 1 );}
wait( NULL ); // parent-process will sleep until the child exitsfclose( rx );fclose( tx );continue;}
‘mywebsvr.cpp’
• We posted this miniature web-server on our course website for you to download
• You can use Linux’s ‘Firefox’ browser to see if indeed it can deliver the sample HTML-file (named ‘mywebpage.html’)
• First start the web-server application, then launch ‘Firefox’ and type in this URL:
<http://hrn235xx:54321/mywebpage.html>
Your classroom host’s station-number
In-class exercise #1
• Try using Microsoft’s Internet Explorer to request the ‘mywebpage.html’ document
• Edit your copy of ‘mywebpage.html’ to add the following attributes within the <body> tag in that HTML document:
<body text=“#00FF00” bgcolor=“#0000FF”>
In-class exercise #2
• Copy the file named ‘warrior.jpg’ from our course website into your local directory
• Then modify the ‘mywebpage.html’ file by adding this extra line in front of </body>:
<img src=“warrior.jpg”>
• Now extend the functionality of our ‘mini’ web-server by adding a block of new code which enables a child-process to deliver an image-file having the ‘.jpg’ file-suffix
Exercise #2 (continued)
• You can do this with your Editor by using ‘copy-and-paste’ applied to the code-block that delivers an ‘html’ file to a client – just change the ‘html’ file-suffix to ‘jpg’, and change the ‘Content-type’ statement so that ‘text/html’ becomes ‘image/jpeg”