History

now answers GET requests

John Floren committed 14 years ago

Commit 4e560141 parent c4e79de5 files · +211 −16Browse files

Unified · Split

5 files
  1. README +3 −0
  2. dat.h +23 −0
  3. fns.h +4 −2
  4. plan9.c +132 −12
  5. util.c +49 −2
README+3−0
@@ -0,0 +1,3 @@
1+This is meant to be an extremely simple HTTP server for benchmarking Plan 9 and POSIX-compliant operating systems.
2+
3+The HTTP parsing and many other parts of the code are based on Paul Griffith's "webserv", being one of the smallest, simplest, and easiest to read HTTP servers I've found online. Like webserv, this server is *not* meant to be used for production in any form, as it utterly lacks any security precautions.
dat.h+23−0
@@ -5,3 +5,26 @@ enum · 4 unmodified lines
55 BufSize = 32*1024,
66 MaxLineLen = 1024,
77 };
8+
9+enum Method
10+{
11+ GET,
12+ UNSUPPORTED
13+};
14+
15+enum Type
16+{
17+ SIMPLE,
18+ FULL
19+};
20+
21+typedef struct Request {
22+ enum Method method;
23+ enum Type type;
24+ char *referer;
25+ char *useragent;
26+ char *resource;
27+ int status;
28+} Request;
29+
30+static char* root = "/tmp";
fns.h+4−2
@@ -1,2 +1,4 @@
1−int Readline(int sockd, void *vptr, int maxlen);
2−int Trim(char* buffer);
1+int readline(int sockd, void *vptr, int maxlen);
2+int writeline(int sockd, void *vptr, int maxlen);
3+int trim(char* buffer);
4+void cleanURL(char* buffer);
plan9.c+132−12
@@ -4,21 +4,146 @@ · 3 unmodified lines
44 #include <fns.h>
55 #include <dat.h>
66
7+int
8+parse(char *buf, Request *req)
9+{
10+ static int first_header = 1; // interesting
11+ char *endptr;
12+ int len;
13+
14+ if (first_header) {
15+ if (!strncmp(buf, "GET ", 4)) {
16+ req->method = GET;
17+ buf += 4;
18+ } else {
19+ req->method = UNSUPPORTED;
20+ req->status = 501;
21+ }
22+
23+ while (*buf && isspace(*buf))
24+ buf++;
25+
26+ endptr = strchr(buf, ' ');
27+ if (endptr == 0)
28+ len = strlen(buf);
29+ else
30+ len = endptr - buf;
31+ if (!len) {
32+ req->status = 400;
33+ return -1;
34+ }
35+
36+ req->resource = calloc(len+1, sizeof(char));
37+ strncpy(req->resource, buf, len);
38+
39+ if (strstr(buf, "HTTP/"))
40+ req->type = FULL;
41+ else
42+ req->type = SIMPLE;
43+
44+ first_header = 0;
45+ return 0;
46+ }
47+ return 0;
48+}
49+
50+void
51+reqinit(Request *req)
52+{
53+ req->status = 200;
54+}
55+
56+int
57+openresource(Request *req)
58+{
59+ cleanURL(req->resource);
60+ strcat(root, req->resource);
61+ return open(root, OREAD);
62+}
63+
64+void
65+outputheaders(int fd, Request *req)
66+{
67+ char buf[100];
68+ sprint(buf, "HTTP/1.0 %d OK\r\r", req->status);
69+ writeline(fd, buf, strlen(buf));
70+
71+ writeline(fd, "Server: httpbench\r\n", strlen("Server: httpbench\r\n"));
72+ writeline(fd, "Content-Type: text/html\r\n", 25);
73+ writeline(fd, "\r\n", 2);
74+}
75+
76+int
77+sendresource(int conn, int resource)
78+{
79+ char c;
80+ int i;
81+
82+ while ( (i = read(resource, &c, 1)) ) {
83+ if ( i < 0 )
84+ exits("Error reading from file.");
85+ if ( write(conn, &c, 1) < 1 )
86+ exits("Error sending file.");
87+ }
88+
89+ return 0;
90+}
91+
92+int
93+senderror(int conn, Request* reqinfo)
94+{
95+
96+ char buffer[100];
97+
98+ sprint(buffer, "<HTML>\n<HEAD>\n<TITLE>Server Error %d</TITLE>\n"
99+ "</HEAD>\n\n", reqinfo->status);
100+ writeline(conn, buffer, strlen(buffer));
101+
102+ sprint(buffer, "<BODY>\n<H1>Server Error %d</H1>\n", reqinfo->status);
103+ writeline(conn, buffer, strlen(buffer));
104+
105+ sprint(buffer, "<P>The request could not be completed.</P>\n"
106+ "</BODY>\n</HTML>\n");
107+ writeline(conn, buffer, strlen(buffer));
108+
109+ return 0;
110+
111+}
112+
7113 void
8114 handler(int fd)
9115 {
10116 char buffer[MaxLineLen] = {0};
117+ Request req;
118+ int rfd; // resource fd
11119
12− print("new connection\n");
120+ reqinit(&req);
13121
14122 alarm(TIMEOUT);
15123 do {
16− Readline(fd, buffer, MaxLineLen - 1);
17− Trim(buffer);
18− print("read: %s\n", buffer);
19− } while (1);
124+ readline(fd, buffer, MaxLineLen - 1);
125+ trim(buffer);
126+ if (buffer[0] == '\0')
127+ break;
128+ if (parse(buffer, &req))
129+ break;
130+ } while (req.type != SIMPLE);
20131 alarm(0);
21− print("done\n");
132+
133+ rfd = openresource(&req); // make sure the resource exists
134+ if (rfd < 0)
135+ req.status = 404;
136+
137+ if (req.type == FULL)
138+ outputheaders(fd, &req);
139+
140+ if (req.status == 200) {
141+ if (sendresource(fd, rfd))
142+ exits("something bad happened while sending the resource\n");
143+ } else {
144+ senderror(fd, &req);
145+ }
146+ exits(0);
22147 }
23148
24149 // This started life as a straight rip-off from dial(2)
@@ -27,8 +152,6 @@ main() · 2 unmodified lines
27152 {
28153 int dfd, acfd, lcfd;
29154 char adir[40], ldir[40];
30− int n;
31− char buf[256];
32155
33156 acfd = announce("tcp!*!8080", adir);
34157 if (acfd < 0)
@@ -50,10 +173,7 @@ main() · 15 unmodified lines
50173 exits("accept failed");
51174
52175 handler(dfd);
53− /* echo until EOF */
54− //while((n = read(dfd, buf, sizeof(buf))) > 0)
55− // write(dfd, buf, n);
56− exits(0);
176+ exits(0); // should never get here
57177 default:
58178 close(lcfd);
59179 break;
util.c+49−2
@@ -11,7 +11,9 @@ · 10 unmodified lines
1111 W Richard Stevens.
1212 */
1313
14−int Readline(int sockd, void *vptr, int maxlen) {
14+int
15+readline(int sockd, void *vptr, int maxlen)
16+{
1517 int n, rc;
1618 char c, *buffer;
1719
@@ -36,9 +38,30 @@ int Readline(int sockd, void *vptr, int maxlen) { · 18 unmodified lines
3638 return n;
3739 }
3840
41+int writeline(int sockd, const void *vptr, int n) {
42+ int nleft;
43+ int nwritten;
44+ const char *buffer;
45+
46+ buffer = vptr;
47+ nleft = n;
48+
49+ while ( nleft > 0 ) {
50+ if ( (nwritten = write(sockd, buffer, nleft)) <= 0 ) {
51+ exits("Error in writeline()");
52+ }
53+ nleft -= nwritten;
54+ buffer += nwritten;
55+ }
56+
57+ return n;
58+}
59+
3960 /* Removes trailing whitespace from a string, also shamelessly ripped from Griffith */
4061
41−int Trim(char * buffer) {
62+int
63+trim(char * buffer)
64+{
4265 int n = strlen(buffer) - 1;
4366
4467 while ( !isalnum(buffer[n]) && n >= 0 )
@@ -46,3 +69,27 @@ int Trim(char * buffer) { · 1 unmodified line
4669
4770 return 0;
4871 }
72+
73+/* Cleans up url-encoded string... guess where this function originates ☺ */
74+
75+void
76+cleanURL(char * buffer)
77+{
78+ char asciinum[3] = {0};
79+ int i = 0, c;
80+
81+ while ( buffer[i] ) {
82+ if ( buffer[i] == '+' )
83+ buffer[i] = ' ';
84+ else if ( buffer[i] == '%' ) {
85+ asciinum[0] = buffer[i+1];
86+ asciinum[1] = buffer[i+2];
87+ buffer[i] = strtol(asciinum, 0, 16);
88+ c = i+1;
89+ do {
90+ buffer[c] = buffer[c+2];
91+ } while ( buffer[2+(c++)] );
92+ }
93+ ++i;
94+ }
95+}