I'm almost through the end of debugging my Pset 6 (Server) code. The server now implements cat.jpg and cat.html properly, but I'm still facing trouble when I try to insert anything into hello.html. I don't get much info from Chrome since it says in the network tab that the status is 200. Anyway, when I try to put any name in hello.html, I get this error in Chrome:
And here's what I get in my terminal window:
GET /hello.html HTTP/1.1
HTTP/1.1 200 OK
GET /hello.php?name=Alice HTTP/1.1
PHP Notice: Undefined index: name in /home/jharvard/Dropbox/pset6/public/hello.php on line 8
PHP Stack trace:
PHP 1. {main}() /home/jharvard/Dropbox/pset6/public/hello.php:0
HTTP/1.1 200 OK
Here's all the relevant code that I wrote:
// TODO: validate request line
// mark up white spaces in line string
int first_space = 0, second_space = 0, extra_space = 0;
for (int i = 0, length = strlen(line); i < length; i += 1)
{
if ((line[i] == ' ') && (first_space == 0))
{
first_space = i;
}
else if ((line[i] == ' ') && (second_space == 0))
{
second_space = i;
}
else if ((line[i] == ' ') && (second_space != 0) && (first_space != 0))
{
extra_space = i;
}
}
// test for error(400)
if ((extra_space != 0) || (first_space == 0) || (second_space == 0) || (line[strlen(line) - 2] != '\r') || (line[strlen(line) - 1] != '\n'))
{
error(400);
}
// make sure method is GET
char method[first_space + 1];
for (int i = 0; i < first_space; i += 1)
{
method[i] = line[i];
}
method[first_space] = '\0';
if (strcmp(method, "GET") != 0)
{
error(405);
}
// make sure request-target begins with a /
if (line[first_space + 1] != '/')
{
error(501);
}
// make sure request-target does not contain a "
for (int i = first_space + 1; i < second_space; i += 1)
{
if (line[i] == '"')
{
error(400);
}
}
// make sure http version is 1.1
char http_version[9];
for (int i = second_space + 1, j = 0; j < 8; i += 1, j+= 1)
{
http_version[j] = line[i];
}
http_version[8] = '\0';
if (strcmp(http_version, "HTTP/1.1") != 0)
{
error(505);
}
// make sure absolute-path contains a . (for the file extension)
bool found_extension = false;
int extension_index = 0;
int start_of_query = 0;
int length_absolute_path = 0;
for (int i = first_space + 1; i < second_space; i += 1)
{
length_absolute_path += 1;
if (line[i] == '.')
{
extension_index = i;
found_extension = true;
}
else if (line[i] == '?')
{
length_absolute_path -= 1;
start_of_query = i;
break;
}
}
if (!found_extension)
{
error(501);
}
// TODO: extract query from request-target
char query[second_space - start_of_query];
if ((start_of_query != 0) || (start_of_query + 1 != second_space))
{
for (int i = start_of_query, j = 0; (i < second_space) && (i + 1 < second_space); i += 1, j += 1)
{
query[j] = line[i];
}
query[second_space - start_of_query] = '\0';
}
if ((start_of_query == 0) || (start_of_query + 1 == second_space))
{
query[0] = '\0';
}
// TODO: concatenate root and absolute-path
char path[strlen(root) + length_absolute_path + 1];
strcpy(path, root);
for (int i = first_space + 1, j = strlen(root); i < first_space + length_absolute_path + 1; i++, j++)
{
path[j] = line[i];
}
path[strlen(root) + length_absolute_path] = '\0';
// TODO: ensure path exists
if (access(path, F_OK) != 0)
{
error(404);
}
// TODO: ensure path is readable
if (access(path, R_OK) != 0)
{
error(403);
}
// TODO: extract path's extension
char extension[10];
int markup_number;
for (int i = first_space + (extension_index - first_space) + 1, j = 0; (line[i] != '?') && (i < second_space); i += 1, j += 1)
{
extension[j] = line[i];
markup_number = j + 1;
}
extension[markup_number] = '\0';
// dynamic content
if (strcasecmp("php", extension) == 0)
{
// open pipe to PHP interpreter
char* format = "QUERY_STRING=\"%s\" REDIRECT_STATUS=200 SCRIPT_FILENAME=\"%s\" php-cgi";
char command[strlen(format) + (strlen(path) - 2) + (strlen(query) - 2) + 1];
sprintf(command, format, query, path);
file = popen(command, "r");
if (file == NULL)
{
error(500);
continue;
}
// load file
ssize_t size = load();
if (size == -1)
{
error(500);
continue;
}
// subtract php-cgi's headers from body's size to get content's length
haystack = body;
needle = memmem(haystack, size, "\r\n\r\n", 4);
if (needle == NULL)
{
error(500);
continue;
}
size_t length = size - (needle - haystack + 4);
// respond to client
if (dprintf(cfd, "HTTP/1.1 200 OK\r\n") < 0)
{
continue;
}
if (dprintf(cfd, "Connection: close\r\n") < 0)
{
continue;
}
if (dprintf(cfd, "Content-Length: %i\r\n", length) < 0)
{
continue;
}
if (write(cfd, body, size) == -1)
{
continue;
}
}
// static content
else
{
// look up file's MIME type
const char* type = lookup(extension);
if (type == NULL)
{
error(501);
continue;
}
// open file
file = fopen(path, "r");
if (file == NULL)
{
error(500);
continue;
}
// load file
ssize_t length = load();
if (length == -1)
{
error(500);
continue;
}
// TODO: respond to client
if (dprintf(cfd, "HTTP/1.1 200 OK\r\n") < 0)
{
continue;
}
if (dprintf(cfd, "Connection: close\r\n") < 0)
{
continue;
}
if (dprintf(cfd, "Content-Length: %i\r\n", length) < 0)
{
continue;
}
if (dprintf(cfd, "Content-Type: %s\r\n\r\n", type) < 0)
{
continue;
}
if (write(cfd, body, length) == -1)
{
continue;
}
}
// announce OK
printf("\033[32m");
printf("HTTP/1.1 200 OK");
printf("\033[39m\n");
}
}
}
/**
* Returns MIME type for supported extensions, else NULL.
*/
const char* lookup(const char* extension)
{
if (strcasecmp("css", extension) == 0)
{
return "text/css";
}
else if (strcasecmp("html", extension) == 0)
{
return "text/html";
}
else if (strcasecmp("gif", extension) == 0)
{
return "image/gif";
}
else if (strcasecmp("ico", extension) == 0)
{
return "image/x-icon";
}
else if (strcasecmp("jpg", extension) == 0)
{
return "image/jpeg";
}
else if (strcasecmp("js", extension) == 0)
{
return "text/javascript";
}
else if (strcasecmp("png", extension) == 0)
{
return "image/png";
}
else
{
return NULL;
}
}
Thank you everyone in advance!