* same with xv6
[mascara-docs.git] / i386 / MIT / course / src / src.lab / user / httpd.c
blob01ddc3d14542917f1ab994be1114856de7cd83e4
1 #include <inc/lib.h>
2 #include <lwip/sockets.h>
3 #include <lwip/inet.h>
5 #define PORT 80
6 #define VERSION "0.1"
7 #define HTTP_VERSION "1.0"
9 #define E_BAD_REQ 1000
11 #define BUFFSIZE 512
12 #define MAXPENDING 5 // Max connection requests
14 struct http_request {
15 int sock;
16 char *url;
17 char *version;
20 struct responce_header {
21 int code;
22 char *header;
25 struct responce_header headers[] = {
26 { 200, "HTTP/" HTTP_VERSION " 200 OK\r\n"
27 "Server: jhttpd/" VERSION "\r\n"},
28 {0, 0},
31 struct error_messages {
32 int code;
33 char *msg;
36 struct error_messages errors[] = {
37 {400, "Bad Request"},
38 {404, "Not Found"},
41 static void
42 die(char *m)
44 cprintf("%s\n", m);
45 exit();
48 static void
49 req_free(struct http_request *req)
51 free(req->url);
52 free(req->version);
55 static int
56 send_header(struct http_request *req, int code)
58 struct responce_header *h = headers;
59 while (h->code != 0 && h->header!= 0) {
60 if (h->code == code)
61 break;
62 h++;
65 if (h->code == 0)
66 return -1;
68 int len = strlen(h->header);
69 if (write(req->sock, h->header, len) != len) {
70 die("Failed to send bytes to client");
73 return 0;
76 static int
77 send_data(struct http_request *req, int fd)
79 // LAB 6: Your code here.
80 panic("send_data not implemented");
83 static int
84 send_size(struct http_request *req, off_t size)
86 char buf[64];
87 int r;
89 r = snprintf(buf, 64, "Content-Length: %ld\r\n", (long)size);
90 if (r > 63)
91 panic("buffer too small!");
93 if (write(req->sock, buf, r) != r)
94 return -1;
96 return 0;
99 static const char*
100 mime_type(const char *file)
102 //TODO: for now only a single mime type
103 return "text/html";
106 static int
107 send_content_type(struct http_request *req)
109 char buf[128];
110 int r;
111 const char *type;
113 type = mime_type(req->url);
114 if (!type)
115 return -1;
117 r = snprintf(buf, 128, "Content-Type: %s\r\n", type);
118 if (r > 127)
119 panic("buffer too small!");
121 if (write(req->sock, buf, r) != r)
122 return -1;
124 return 0;
127 static int
128 send_header_fin(struct http_request *req)
130 const char *fin = "\r\n";
131 int fin_len = strlen(fin);
133 if (write(req->sock, fin, fin_len) != fin_len)
134 return -1;
136 return 0;
139 // given a request, this function creates a struct http_request
140 static int
141 http_request_parse(struct http_request *req, char *request)
143 const char *url;
144 const char *version;
145 int url_len, version_len;
147 if (!req)
148 return -1;
150 if (strncmp(request, "GET ", 4) != 0)
151 return -E_BAD_REQ;
153 // skip GET
154 request += 4;
156 // get the url
157 url = request;
158 while (*request && *request != ' ')
159 request++;
160 url_len = request - url;
162 req->url = malloc(url_len + 1);
163 memmove(req->url, url, url_len);
164 req->url[url_len] = '\0';
166 // skip space
167 request++;
169 version = request;
170 while (*request && *request != '\n')
171 request++;
172 version_len = request - version;
174 req->version = malloc(version_len + 1);
175 memmove(req->version, version, version_len);
176 req->version[version_len] = '\0';
178 // no entity parsing
180 return 0;
183 static int
184 send_error(struct http_request *req, int code)
186 char buf[512];
187 int r;
189 struct error_messages *e = errors;
190 while (e->code != 0 && e->msg != 0) {
191 if (e->code == code)
192 break;
193 e++;
196 if (e->code == 0)
197 return -1;
199 r = snprintf(buf, 512, "HTTP/" HTTP_VERSION" %d %s\r\n"
200 "Server: jhttpd/" VERSION "\r\n"
201 "Connection: close"
202 "Content-type: text/html\r\n"
203 "\r\n"
204 "<html><body><p>%d - %s</p></body></html>\r\n",
205 e->code, e->msg, e->code, e->msg);
207 if (write(req->sock, buf, r) != r)
208 return -1;
210 return 0;
213 static int
214 send_file(struct http_request *req)
216 int r;
217 off_t file_size = -1;
218 int fd;
220 // open the requested url for reading
221 // if the file does not exist, send a 404 error using send_error
222 // if the file is a directory, send a 404 error using send_error
223 // set file_size to the size of the file
225 // LAB 6: Your code here.
226 panic("send_file not implemented");
228 if ((r = send_header(req, 200)) < 0)
229 goto end;
231 if ((r = send_size(req, file_size)) < 0)
232 goto end;
234 if ((r = send_content_type(req)) < 0)
235 goto end;
237 if ((r = send_header_fin(req)) < 0)
238 goto end;
240 r = send_data(req, fd);
242 end:
243 close(fd);
244 return r;
247 static void
248 handle_client(int sock)
250 struct http_request con_d;
251 int r;
252 char buffer[BUFFSIZE];
253 int received = -1;
254 struct http_request *req = &con_d;
256 while (1)
258 // Receive message
259 if ((received = read(sock, buffer, BUFFSIZE)) < 0)
260 panic("failed to read");
262 memset(req, 0, sizeof(req));
264 req->sock = sock;
266 r = http_request_parse(req, buffer);
267 if (r == -E_BAD_REQ)
268 send_error(req, 400);
269 else if (r < 0)
270 panic("parse failed");
271 else
272 send_file(req);
274 req_free(req);
276 // no keep alive
277 break;
280 close(sock);
283 void
284 umain(int argc, char **argv)
286 int serversock, clientsock;
287 struct sockaddr_in server, client;
289 binaryname = "jhttpd";
291 // Create the TCP socket
292 if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
293 die("Failed to create socket");
295 // Construct the server sockaddr_in structure
296 memset(&server, 0, sizeof(server)); // Clear struct
297 server.sin_family = AF_INET; // Internet/IP
298 server.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
299 server.sin_port = htons(PORT); // server port
301 // Bind the server socket
302 if (bind(serversock, (struct sockaddr *) &server,
303 sizeof(server)) < 0)
305 die("Failed to bind the server socket");
308 // Listen on the server socket
309 if (listen(serversock, MAXPENDING) < 0)
310 die("Failed to listen on server socket");
312 cprintf("Waiting for http connections...\n");
314 while (1) {
315 unsigned int clientlen = sizeof(client);
316 // Wait for client connection
317 if ((clientsock = accept(serversock,
318 (struct sockaddr *) &client,
319 &clientlen)) < 0)
321 die("Failed to accept client connection");
323 handle_client(clientsock);
326 close(serversock);