Previous: Steps in Implementing an Insecure HTTP Client, Up: Implementing an Insecure HTTP Client [Index]
This is the full code listing for the Insecure HTTP Client.
1 /**
2 * This test utility does simple (non-encrypted) HTTP
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <netdb.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <unistd.h>
14
15 #define HTTP_PORT 80
16 #define BUFFER_SIZE 255
17 #define MAX_GET_COMMAND 255
18
19 /**
20 * Accept a well-formed URL (e.g. http://www.company.com/index.html) and return
21 * pointers to the host part and the path part. Note that this function
22 * modifies the uri itself as well. It returns 0 on success, -1 if the URL is
23 * found to be malformed in any way.
24 */
25
26 int parse_url( char *uri, char **host, char **path )
27 {
28 char *pos;
29
30 pos = strstr( uri, "//" );
31
32 if ( !pos )
33 {
34 return -1;
35 }
36
37 *host = pos + 2;
38
39 pos = strchr( *host, '/' );
40
41 if ( !pos )
42 {
43 *path = NULL;
44 }
45 else
46 {
47 *pos = '\0';
48 *path = pos + 1;
49 }
50
51 return 0;
52 }
53
54 /**
55 * Format and send an HTTP get command. The return value will be 0 on
56 * success, -1 on failure, with errno set appropriately. The caller
57 * must then retrieve the response.
58 */
59
60 int http_get( int connection, const char *path, const char *host )
61 {
62 static char get_command[ MAX_GET_COMMAND ];
63
64 sprintf( get_command, "GET /%s HTTP/1.1\r\n", path );
65 if ( send( connection, get_command, strlen( get_command ), 0 ) == -1 )
66 {
67 return -1;
68 }
69
70 sprintf( get_command, "Host: %s\r\n", host );
71 if ( send( connection, get_command, strlen( get_command ), 0 ) == -1 )
72 {
73 return -1;
74 }
75
76 sprintf( get_command, "Connection: close\r\n\r\n" );
77 if ( send( connection, get_command, strlen( get_command ), 0 ) == -1 )
78 {
79 return -1;
80 }
81
82 return 0;
83 }
84
85 /**
86 * Receive all data available on a connection and dump it to stdout
87 */
88
89 void display_result( int connection )
90 {
91 int received = 0;
92
93 static char recv_buf[ BUFFER_SIZE + 1 ];
94
95 while ( ( received = recv( connection, recv_buf, BUFFER_SIZE, 0 ) ) > 0 )
96 {
97 recv_buf[ received ] = '\0';
98 printf( "%s", recv_buf );
99 }
100
101 printf( "\n" );
102 }
103
104 /**
105 * Simple command-line HTTP client.
106 */
107
108 int main( int argc, char *argv[ ] )
109 {
110 int client_connection;
111 char *host, *path;
112 struct hostent *host_name;
113 struct sockaddr_in host_address;
114
115 if ( argc < 2 )
116 {
117 fprintf( stderr, "Usage: %s: <URL>\n", argv[ 0 ] );
118 return 1;
119 }
120
121 if ( parse_url( argv[ 1 ], &host, &path ) == -1 )
122 {
123 fprintf( stderr, "Error - malformed URL '%s . \n", argv[ 1 ] );
124 return 1;
125 }
126
127 printf( "Conecting to host '%s'\n", host );
128
129 // Step 1: open a socket connection on http port with the destination host
130
131 client_connection = socket( PF_INET, SOCK_STREAM, 0 );
132
133 if ( !client_connection )
134 {
135 perror( "Unable to create a local socket" );
136 return 2;
137 }
138
139 host_name = gethostbyname( host );
140
141 if ( !host_name )
142 {
143 perror( "Error in name resolution" );
144 return 3;
145 }
146
147 host_address.sin_family = AF_INET;
148 host_address.sin_port = htons( HTTP_PORT );
149 memcpy( &host_address.sin_addr, host_name->h_addr_list[ 0 ],
150 sizeof( struct in_addr ) );
151
152 if ( connect( client_connection, ( struct sockaddr * ) &host_address,
153 sizeof( host_address ) ) == -1 )
154 {
155 perror( "Unable to connect to host" );
156 return 4;
157 }
158
159 printf( "Retrieving document: '%s'\n", path );
160
161 // Step 2: Issue a GET command
162
163 http_get( client_connection, path, host );
164
165 display_result( client_connection );
166
167 printf( "Shutting down.\n" );
168
169 if (close( client_connection ) == -1 )
170 {
171 perror( "Error closing client connection" );
172 return 5;
173 }
174
175 return 0;
176 }
177