Skip to content

Commit

Permalink
final
Browse files Browse the repository at this point in the history
  • Loading branch information
yhayun committed Jun 3, 2017
1 parent 95182fb commit f85deec
Show file tree
Hide file tree
Showing 2 changed files with 370 additions and 3 deletions.
27 changes: 24 additions & 3 deletions user/httpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,17 @@ static int
send_data(struct http_request *req, int fd)
{
// LAB 6: Your code here.
panic("send_data not implemented");
int read_size;
char buf[512];
while ( (read_size = read(fd, buf, 512)) > 0 ){
if (write(req->sock, buf, read_size) != read_size)
return -1;

}
if ( read_size < 0)
return -1;

return 0;
}

static int
Expand Down Expand Up @@ -215,15 +225,26 @@ send_file(struct http_request *req)
{
int r;
off_t file_size = -1;
int fd;
int fd = 0;

// open the requested url for reading
// if the file does not exist, send a 404 error using send_error
// if the file is a directory, send a 404 error using send_error
// set file_size to the size of the file

// LAB 6: Your code here.
panic("send_file not implemented");
struct Stat fd_stat;
if (( r = open(req->url, O_RDONLY)) < 0 ){
send_error(req, 404);
return r;
}
fd = r;

if (( r = stat(req->url, &fd_stat)) < 0 || fd_stat.st_isdir) {
send_error(req, 404);
goto end;
}
file_size = fd_stat.st_size;

if ((r = send_header(req, 200)) < 0)
goto end;
Expand Down
346 changes: 346 additions & 0 deletions user/httpd.c~
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
#include <inc/lib.h>
#include <lwip/sockets.h>
#include <lwip/inet.h>

#define PORT 80
#define VERSION "0.1"
#define HTTP_VERSION "1.0"

#define E_BAD_REQ 1000

#define BUFFSIZE 512
#define MAXPENDING 5 // Max connection requests

struct http_request {
int sock;
char *url;
char *version;
};

struct responce_header {
int code;
char *header;
};

struct responce_header headers[] = {
{ 200, "HTTP/" HTTP_VERSION " 200 OK\r\n"
"Server: jhttpd/" VERSION "\r\n"},
{0, 0},
};

struct error_messages {
int code;
char *msg;
};

struct error_messages errors[] = {
{400, "Bad Request"},
{404, "Not Found"},
};

static void
die(char *m)
{
cprintf("%s\n", m);
exit();
}

static void
req_free(struct http_request *req)
{
free(req->url);
free(req->version);
}

static int
send_header(struct http_request *req, int code)
{
struct responce_header *h = headers;
while (h->code != 0 && h->header!= 0) {
if (h->code == code)
break;
h++;
}

if (h->code == 0)
return -1;

int len = strlen(h->header);
if (write(req->sock, h->header, len) != len) {
die("Failed to send bytes to client");
}

return 0;
}

static int
send_data(struct http_request *req, int fd)
{
// LAB 6: Your code here.
int read_size;
char buf[512];
while ( (read_size = read(fd, buf, 512)) > 0 ){
if (write(req->sock, buf, read_size) != read_size)
die("send_data: unable to write data to socket\n");

}

return 0;
}

static int
send_size(struct http_request *req, off_t size)
{
char buf[64];
int r;

r = snprintf(buf, 64, "Content-Length: %ld\r\n", (long)size);
if (r > 63)
panic("buffer too small!");

if (write(req->sock, buf, r) != r)
return -1;

return 0;
}

static const char*
mime_type(const char *file)
{
//TODO: for now only a single mime type
return "text/html";
}

static int
send_content_type(struct http_request *req)
{
char buf[128];
int r;
const char *type;

type = mime_type(req->url);
if (!type)
return -1;

r = snprintf(buf, 128, "Content-Type: %s\r\n", type);
if (r > 127)
panic("buffer too small!");

if (write(req->sock, buf, r) != r)
return -1;

return 0;
}

static int
send_header_fin(struct http_request *req)
{
const char *fin = "\r\n";
int fin_len = strlen(fin);

if (write(req->sock, fin, fin_len) != fin_len)
return -1;

return 0;
}

// given a request, this function creates a struct http_request
static int
http_request_parse(struct http_request *req, char *request)
{
const char *url;
const char *version;
int url_len, version_len;

if (!req)
return -1;

if (strncmp(request, "GET ", 4) != 0)
return -E_BAD_REQ;

// skip GET
request += 4;

// get the url
url = request;
while (*request && *request != ' ')
request++;
url_len = request - url;

req->url = malloc(url_len + 1);
memmove(req->url, url, url_len);
req->url[url_len] = '\0';

// skip space
request++;

version = request;
while (*request && *request != '\n')
request++;
version_len = request - version;

req->version = malloc(version_len + 1);
memmove(req->version, version, version_len);
req->version[version_len] = '\0';

// no entity parsing

return 0;
}

static int
send_error(struct http_request *req, int code)
{
char buf[512];
int r;

struct error_messages *e = errors;
while (e->code != 0 && e->msg != 0) {
if (e->code == code)
break;
e++;
}

if (e->code == 0)
return -1;

r = snprintf(buf, 512, "HTTP/" HTTP_VERSION" %d %s\r\n"
"Server: jhttpd/" VERSION "\r\n"
"Connection: close"
"Content-type: text/html\r\n"
"\r\n"
"<html><body><p>%d - %s</p></body></html>\r\n",
e->code, e->msg, e->code, e->msg);

if (write(req->sock, buf, r) != r)
return -1;

return 0;
}

static int
send_file(struct http_request *req)
{
int r;
off_t file_size = -1;
int fd = 0;

// open the requested url for reading
// if the file does not exist, send a 404 error using send_error
// if the file is a directory, send a 404 error using send_error
// set file_size to the size of the file

// LAB 6: Your code here.
struct Stat fd_stat;
if (( r = open(req->url, O_RDONLY)) < 0 ){
send_error(req, 404);
return r;
}
fd = r;

if (( r = stat(req->url, &fd_stat)) < 0 || fd_stat.st_isdir) {
send_error(req, 404);
goto end;
}
file_size = fd_stat.st_size;

if ((r = send_header(req, 200)) < 0)
goto end;

if ((r = send_size(req, file_size)) < 0)
goto end;

if ((r = send_content_type(req)) < 0)
goto end;

if ((r = send_header_fin(req)) < 0)
goto end;

r = send_data(req, fd);

end:
close(fd);
return r;
}

static void
handle_client(int sock)
{
struct http_request con_d;
int r;
char buffer[BUFFSIZE];
int received = -1;
struct http_request *req = &con_d;

while (1)
{
// Receive message
if ((received = read(sock, buffer, BUFFSIZE)) < 0)
panic("failed to read");

memset(req, 0, sizeof(req));

req->sock = sock;

r = http_request_parse(req, buffer);
if (r == -E_BAD_REQ)
send_error(req, 400);
else if (r < 0)
panic("parse failed");
else
send_file(req);

req_free(req);

// no keep alive
break;
}

close(sock);
}

void
umain(int argc, char **argv)
{
int serversock, clientsock;
struct sockaddr_in server, client;

binaryname = "jhttpd";

// Create the TCP socket
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
die("Failed to create socket");

// Construct the server sockaddr_in structure
memset(&server, 0, sizeof(server)); // Clear struct
server.sin_family = AF_INET; // Internet/IP
server.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
server.sin_port = htons(PORT); // server port

// Bind the server socket
if (bind(serversock, (struct sockaddr *) &server,
sizeof(server)) < 0)
{
die("Failed to bind the server socket");
}

// Listen on the server socket
if (listen(serversock, MAXPENDING) < 0)
die("Failed to listen on server socket");

cprintf("Waiting for http connections...\n");

while (1) {
unsigned int clientlen = sizeof(client);
// Wait for client connection
if ((clientsock = accept(serversock,
(struct sockaddr *) &client,
&clientlen)) < 0)
{
die("Failed to accept client connection");
}
handle_client(clientsock);
}

close(serversock);
}

0 comments on commit f85deec

Please sign in to comment.