I've have been working on this problem set for quite some time now and I thought I have completed it. All of the functions were working fine when I used Telnet to submit the requests. My program is able to return "/hello.html" as per the right terminal window (https://i.sstatic.net/K14aY.png) when I submit a request "GET /hello.html HTTP/1.1".
However, when I tried accessing "###.###.###.###:8080/hello.html" on Chrome (https://i.sstatic.net/fpXoK.png), I was not able to get the html page as it says "405 Method Not Allowed". Curiously, when I look at the terminal window (in the same screenshot) where I ran my server, the requests I made on Telnet and Chrome are EXACTLY the same, "GET /hello.html HTTP/1.1". However, now the response is "405 Method Not Allowed" instead of "200 OK". This screenshot (https://i.sstatic.net/xlZt0.png) shows the Developer Tools panel.
The following is the code which I've changed:
// TODO: validate request-line
// Extracting the request-line without the CRLF
char entireline[needle - haystack + 1];
strncpy(entireline, haystack, needle - haystack);
entireline[needle - haystack] = '\0';
// Extract method from request-line
char* endofmethod = strchr(entireline, ' ');
char method[strlen(haystack) - strlen(endofmethod) - 1];
strncpy(method, haystack, strlen(haystack) - strlen(endofmethod) - 2);
method[strlen(haystack) - strlen(endofmethod) - 2] = '\0';
// If method is not get
if (method == NULL || strcmp(method, "GET") != 0)
{
error(405);
continue;
}
// Extract request-target from request-line
char* endofrequest = strchr(endofmethod + 1, ' ');
char requestline[strlen(endofmethod)- strlen(endofrequest)];
strncpy(requestline, endofmethod + 1, strlen(endofmethod)- strlen(endofrequest) - 1);
requestline[strlen(endofmethod)- strlen(endofrequest) - 1] = '\0';
// If the requestline does not start with "/"
if (requestline == NULL || requestline[0] != '/')
{
error(501);
continue;
}
// If there are double apostrophes in the requestline
for(int i = 0, n = strlen(requestline); i < n; i++)
{
if (requestline[i] == '"')
{
error(400);
continue;
}
}
// If there are no "." in the "absolute-path" within the requestline
// You will only have endofabspath if you have "?" in your requestline, if not it doesn't exists
// If the middle argument (absolute-path) contains a "?", then "endofabspath" will take 2nd argument. If it does not, it will take the 1st argument
char* endofabspath = (strchr(endofmethod + 1, '?') != NULL) ? strchr(endofmethod + 1, '?') : NULL;
int absLength = (endofabspath != NULL) ? strlen(endofmethod) - strlen(endofabspath) : strlen(requestline) + 1;
char absolutepath[absLength];
// If "request-target" contains a "?"... "absolutepath" will be before the "?"
if (strchr(endofmethod + 1, '?') != NULL)
{
strncpy(absolutepath, endofmethod + 1, strlen(endofmethod) - strlen(endofabspath) - 1);
absolutepath[strlen(endofmethod) - strlen(endofabspath) - 1] = '\0';
// If no "."
if (strstr(absolutepath, ".") == NULL)
{
error(501);
continue;
}
}
// or if "request-target" does not contain a "?"... "absolutepath" will simply be 2nd argument
else
{
strncpy(absolutepath, endofmethod + 1, strlen(requestline));
absolutepath[strlen(requestline)] = '\0';
// If no "."
if (strstr(requestline, ".") == NULL)
{
error(501);
continue;
}
}
char httpversion[strlen(endofrequest)];
strncpy(httpversion, endofrequest + 1, strlen(endofrequest));
httpversion[strlen(endofrequest) - 1] = '\0';
if (strcmp(httpversion, "HTTP/1.1\0") != 0)
{
error(505);
continue;
}
// TODO: extract query from request-target
// "endofabspath" will be "NULL" when there are no "?" within "absolutepath"
int queryLen = (endofabspath != NULL) ? strlen(endofabspath) - strlen(endofrequest) : 1;
char query[queryLen];
if (endofabspath != NULL)
{
strncpy(query, endofabspath + 1, strlen(endofabspath) - strlen(endofrequest) - 1);
query[strlen(endofabspath) - strlen(endofrequest) - 1] = '\0';
}
else
{
query[0] = '\0';
}
// TODO: concatenate root and absolute-path
char path[strlen(root) + strlen(absolutepath) + 1];
strcpy(path, root);
strcpy(path + strlen(root), absolutepath);
path[strlen(root) + strlen(absolutepath)] = '\0';
// TODO: ensure path exists
if (access(path, F_OK) != 0)
{
error(404);
continue;
}
// TODO: ensure path is readable
if (access(path, R_OK) != 0)
{
error(403);
continue;
}
// TODO: extract path's extension
char extension[strlen(strchr(path, '.'))];
strncpy(extension, strchr(path,'.') + 1, strlen(strchr(path,'.')) - 1 );
extension[strlen(strchr(path, '.')) - 1] = '\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");
}
}
}
Will someone please tell me what's wrong? I have been troubled by this problem for hours as I really do not know where to start investigating the problem. I really hope to get it solved, thanks so much in advance!
curl
command and try to get and print the http headers that were return. Or if your familiar with any networking tools you could use that ('wireshark, tcpdump').