The best way to learn the minutue of how web requests are made is to write a web server
in as low a level as practical. It's not actually that hard to use the raw socket libraries
and build something simple in C or C++. This file handles HTTP 1.0 and returns a simple
static doc for every request URI. It also prints the raw HTTP request made by the client to STDOUT
which can be useful sometimes when investigating the behavior of esoteric HTTP clients.
1 #include <ctime>
2 #include <iostream>
3 #include <sstream>
4 #include <string>
5 #include <cstdio>
6 #include <unistd.h>
7
8 9 #include <netinet/in.h> 10 #include <sys/socket.h>
11 #include <sys/types.h>
12
13 using namespace std;
14
15 16 17 string getHeaderTime() {
18 time_t now = time(NULL);
19 struct tm* timeinfo;
20 timeinfo = gmtime(&now);
21
22 char buff[80];
23 memset(buff, 0, sizeof(buff));
24 strftime(buff, 80, "Date: %a, %d %b %Y %X %Z", timeinfo);
25 string s(buff);
26 return s;
27 }
28
29 string get200Header() {
30 stringstream head;
31 head.clear();
32 head << "HTTP/1.0 200 OK" << endl
33 << getHeaderTime() << endl
34 << "Expires: -1" << endl
35 << "Cache-Control: private, max-age=0" << endl
36 << "Content-Type: text/html; charset=ISO-8859-1\r\n\n";
37 return head.str();
38 }
39
40 string getSimpleDoc() {
41 stringstream resp;
42 resp.clear();
43 resp << "<html><head><title>47 Ways to Fun</title></head>"
44 << "<body>Sample Document</body></html>"
45 << "\r\n";
46 return resp.str();
47 }
48
49 int main(int argc, char* argv[]) {
50 static const int kBacklog = 50;
51 static const int kPort = 8000;
52 const string CRLF = "\r\n";
53
54 int listenfd = socket(AF_INET, SOCK_STREAM, 0);
55
56 struct sockaddr_in servaddr;
57 memset(&servaddr, '\0', sizeof(servaddr));
58 servaddr.sin_family = AF_INET;
59 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
60 servaddr.sin_port = htons(kPort);
61
62 if (bind(listenfd, (sockaddr *) &servaddr, sizeof(servaddr)) == -1) {
63 cerr << "Error binding to port: " << kPort << endl;
64 perror("bind error");
65 exit(1);
66 }
67 listen(listenfd, kBacklog);
68
69 int connfd;
70 char buff[1024*8];
71 while (true) {
72 connfd = accept(listenfd, (struct sockaddr *) NULL, NULL);
73 memset(buff, 0, sizeof(buff));
74 recv(connfd, buff, 1024*8, 0);
75 cout << "========================================================" << endl;
76 cout << buff << endl;
77
78 string head = get200Header();
79 write(connfd, head.c_str(), head.length());
80
81 string doc = getSimpleDoc();
82 write(connfd, doc.c_str(), doc.length());
83
84 close(connfd);
85 }
86 return 0;
87 }