Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
remzi-arpacidusseau
GitHub Repository: remzi-arpacidusseau/ostep-projects
Path: blob/master/concurrency-webserver/src/request.c
909 views
1
#include "io_helper.h"
2
#include "request.h"
3
4
//
5
// Some of this code stolen from Bryant/O'Halloran
6
// Hopefully this is not a problem ... :)
7
//
8
9
#define MAXBUF (8192)
10
11
void request_error(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) {
12
char buf[MAXBUF], body[MAXBUF];
13
14
// Create the body of error message first (have to know its length for header)
15
sprintf(body, ""
16
"<!doctype html>\r\n"
17
"<head>\r\n"
18
" <title>OSTEP WebServer Error</title>\r\n"
19
"</head>\r\n"
20
"<body>\r\n"
21
" <h2>%s: %s</h2>\r\n"
22
" <p>%s: %s</p>\r\n"
23
"</body>\r\n"
24
"</html>\r\n", errnum, shortmsg, longmsg, cause);
25
26
// Write out the header information for this response
27
sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
28
write_or_die(fd, buf, strlen(buf));
29
30
sprintf(buf, "Content-Type: text/html\r\n");
31
write_or_die(fd, buf, strlen(buf));
32
33
sprintf(buf, "Content-Length: %lu\r\n\r\n", strlen(body));
34
write_or_die(fd, buf, strlen(buf));
35
36
// Write out the body last
37
write_or_die(fd, body, strlen(body));
38
}
39
40
//
41
// Reads and discards everything up to an empty text line
42
//
43
void request_read_headers(int fd) {
44
char buf[MAXBUF];
45
46
readline_or_die(fd, buf, MAXBUF);
47
while (strcmp(buf, "\r\n")) {
48
readline_or_die(fd, buf, MAXBUF);
49
}
50
return;
51
}
52
53
//
54
// Return 1 if static, 0 if dynamic content
55
// Calculates filename (and cgiargs, for dynamic) from uri
56
//
57
int request_parse_uri(char *uri, char *filename, char *cgiargs) {
58
char *ptr;
59
60
if (!strstr(uri, "cgi")) {
61
// static
62
strcpy(cgiargs, "");
63
sprintf(filename, ".%s", uri);
64
if (uri[strlen(uri)-1] == '/') {
65
strcat(filename, "index.html");
66
}
67
return 1;
68
} else {
69
// dynamic
70
ptr = index(uri, '?');
71
if (ptr) {
72
strcpy(cgiargs, ptr+1);
73
*ptr = '\0';
74
} else {
75
strcpy(cgiargs, "");
76
}
77
sprintf(filename, ".%s", uri);
78
return 0;
79
}
80
}
81
82
//
83
// Fills in the filetype given the filename
84
//
85
void request_get_filetype(char *filename, char *filetype) {
86
if (strstr(filename, ".html"))
87
strcpy(filetype, "text/html");
88
else if (strstr(filename, ".gif"))
89
strcpy(filetype, "image/gif");
90
else if (strstr(filename, ".jpg"))
91
strcpy(filetype, "image/jpeg");
92
else
93
strcpy(filetype, "text/plain");
94
}
95
96
void request_serve_dynamic(int fd, char *filename, char *cgiargs) {
97
char buf[MAXBUF], *argv[] = { NULL };
98
99
// The server does only a little bit of the header.
100
// The CGI script has to finish writing out the header.
101
sprintf(buf, ""
102
"HTTP/1.0 200 OK\r\n"
103
"Server: OSTEP WebServer\r\n");
104
105
write_or_die(fd, buf, strlen(buf));
106
107
if (fork_or_die() == 0) { // child
108
setenv_or_die("QUERY_STRING", cgiargs, 1); // args to cgi go here
109
dup2_or_die(fd, STDOUT_FILENO); // make cgi writes go to socket (not screen)
110
extern char **environ; // defined by libc
111
execve_or_die(filename, argv, environ);
112
} else {
113
wait_or_die(NULL);
114
}
115
}
116
117
void request_serve_static(int fd, char *filename, int filesize) {
118
int srcfd;
119
char *srcp, filetype[MAXBUF], buf[MAXBUF];
120
121
request_get_filetype(filename, filetype);
122
srcfd = open_or_die(filename, O_RDONLY, 0);
123
124
// Rather than call read() to read the file into memory,
125
// which would require that we allocate a buffer, we memory-map the file
126
srcp = mmap_or_die(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
127
close_or_die(srcfd);
128
129
// put together response
130
sprintf(buf, ""
131
"HTTP/1.0 200 OK\r\n"
132
"Server: OSTEP WebServer\r\n"
133
"Content-Length: %d\r\n"
134
"Content-Type: %s\r\n\r\n",
135
filesize, filetype);
136
137
write_or_die(fd, buf, strlen(buf));
138
139
// Writes out to the client socket the memory-mapped file
140
write_or_die(fd, srcp, filesize);
141
munmap_or_die(srcp, filesize);
142
}
143
144
// handle a request
145
void request_handle(int fd) {
146
int is_static;
147
struct stat sbuf;
148
char buf[MAXBUF], method[MAXBUF], uri[MAXBUF], version[MAXBUF];
149
char filename[MAXBUF], cgiargs[MAXBUF];
150
151
readline_or_die(fd, buf, MAXBUF);
152
sscanf(buf, "%s %s %s", method, uri, version);
153
printf("method:%s uri:%s version:%s\n", method, uri, version);
154
155
if (strcasecmp(method, "GET")) {
156
request_error(fd, method, "501", "Not Implemented", "server does not implement this method");
157
return;
158
}
159
request_read_headers(fd);
160
161
is_static = request_parse_uri(uri, filename, cgiargs);
162
if (stat(filename, &sbuf) < 0) {
163
request_error(fd, filename, "404", "Not found", "server could not find this file");
164
return;
165
}
166
167
if (is_static) {
168
if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
169
request_error(fd, filename, "403", "Forbidden", "server could not read this file");
170
return;
171
}
172
request_serve_static(fd, filename, sbuf.st_size);
173
} else {
174
if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
175
request_error(fd, filename, "403", "Forbidden", "server could not run this CGI program");
176
return;
177
}
178
request_serve_dynamic(fd, filename, cgiargs);
179
}
180
}
181
182