0

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!

1
  • 405 means that probably the GET method is not allowed on the server instance. Try to use the 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').
    – Ed Abucay
    Commented May 4, 2015 at 16:31

1 Answer 1

1

Found the bug which has to do with needle and haystack. Needle and haystack give different values on the browser than when in the command-line and hence, "method" isn't "GET". Hence, while it works on the command-line, it doesn't on the browser. Solved it by using the given variable "line" rather than assigning the variable "entireline".

1
  • thanks for letting us know how you solved the issue!
    – David
    Commented May 5, 2015 at 23:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .