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 @@
1This is meant to be an extremely simple HTTP server for benchmarking Plan 9 and POSIX-compliant operating systems.
2
3The 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
5 BufSize = 32*1024,5 BufSize = 32*1024,
6 MaxLineLen = 1024,6 MaxLineLen = 1024,
7};7};
8
9enum Method
10{
11 GET,
12 UNSUPPORTED
13};
14
15enum Type
16{
17 SIMPLE,
18 FULL
19};
20
21typedef 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
30static char* root = "/tmp";
fns.h+4−2
@@ -1,2 +1,4 @@
1int Readline(int sockd, void *vptr, int maxlen);1int readline(int sockd, void *vptr, int maxlen);
2int Trim(char* buffer);2int writeline(int sockd, void *vptr, int maxlen);
3int trim(char* buffer);
4void cleanURL(char* buffer);
plan9.c+132−12
@@ -4,21 +4,146 @@ · 3 unmodified lines
4#include <fns.h>4#include <fns.h>
5#include <dat.h>5#include <dat.h>
6 6
7int
8parse(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
50void
51reqinit(Request *req)
52{
53 req->status = 200;
54}
55
56int
57openresource(Request *req)
58{
59 cleanURL(req->resource);
60 strcat(root, req->resource);
61 return open(root, OREAD);
62}
63
64void
65outputheaders(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
76int
77sendresource(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
92int
93senderror(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
7void113void
8handler(int fd)114handler(int fd)
9{115{
10 char buffer[MaxLineLen] = {0};116 char buffer[MaxLineLen] = {0};
117 Request req;
118 int rfd; // resource fd
11 119
12 print("new connection\n");120 reqinit(&req);
13 121
14 alarm(TIMEOUT);122 alarm(TIMEOUT);
15 do {123 do {
16 Readline(fd, buffer, MaxLineLen - 1);124 readline(fd, buffer, MaxLineLen - 1);
17 Trim(buffer);125 trim(buffer);
18 print("read: %s\n", buffer);126 if (buffer[0] == '\0')
19 } while (1);127 break;
128 if (parse(buffer, &req))
129 break;
130 } while (req.type != SIMPLE);
20 alarm(0);131 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);
22}147}
23 148
24// This started life as a straight rip-off from dial(2)149// This started life as a straight rip-off from dial(2)
@@ -27,8 +152,6 @@ main() · 2 unmodified lines
27{152{
28 int dfd, acfd, lcfd;153 int dfd, acfd, lcfd;
29 char adir[40], ldir[40];154 char adir[40], ldir[40];
30 int n;
31 char buf[256];
32 155
33 acfd = announce("tcp!*!8080", adir);156 acfd = announce("tcp!*!8080", adir);
34 if (acfd < 0)157 if (acfd < 0)
@@ -50,10 +173,7 @@ main() · 15 unmodified lines
50 exits("accept failed");173 exits("accept failed");
51 174
52 handler(dfd);175 handler(dfd);
53 /* echo until EOF */176 exits(0); // should never get here
54 //while((n = read(dfd, buf, sizeof(buf))) > 0)
55 // write(dfd, buf, n);
56 exits(0);
57 default:177 default:
58 close(lcfd);178 close(lcfd);
59 break;179 break;
util.c+49−2
@@ -11,7 +11,9 @@ · 10 unmodified lines
11 W Richard Stevens.11 W Richard Stevens.
12*/12*/
13 13
14int Readline(int sockd, void *vptr, int maxlen) {14int
15readline(int sockd, void *vptr, int maxlen)
16{
15 int n, rc;17 int n, rc;
16 char c, *buffer;18 char c, *buffer;
17 19
@@ -36,9 +38,30 @@ int Readline(int sockd, void *vptr, int maxlen) { · 18 unmodified lines
36 return n;38 return n;
37}39}
38 40
41int 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
39/* Removes trailing whitespace from a string, also shamelessly ripped from Griffith */60/* Removes trailing whitespace from a string, also shamelessly ripped from Griffith */
40 61
41int Trim(char * buffer) {62int
63trim(char * buffer)
64{
42 int n = strlen(buffer) - 1;65 int n = strlen(buffer) - 1;
43 66
44 while ( !isalnum(buffer[n]) && n >= 0 )67 while ( !isalnum(buffer[n]) && n >= 0 )
@@ -46,3 +69,27 @@ int Trim(char * buffer) { · 1 unmodified line
46 69
47 return 0;70 return 0;
48}71}
72
73/* Cleans up url-encoded string... guess where this function originates ☺ */
74
75void
76cleanURL(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}