0

I've looked at other questions on this topic but none of the other code is structured like mine, making it hard to compare. I've fixed all the other errors except for two:

:( HTTP/1.0 returns error code 505
   \ expected output, but not "HTTP/1.1 501 Not Implemented\r\nContent..."

:( Requesting non-existant file returns error code 404
   \ expected output, but not "HTTP/1.1 501 Not Implemented\r\nContent..."

I don't understand why I'm getting these errors since everything else works. I've looked over my code but I can't find anything that would cause these errors. I can't use GDB because of a segmentation fault on query_length = strlen(query), which I'll save for another question. Because of this seg-fault, I can't use printfs on the web server, either. I think it has to do with this test:

if (strcmp(identify, "/") != 0)
{
    error(501);
    return false;
}

I've tried re-arranging my code but that doesn't work. I wonder if it's how I'm testing this?

Here is my code:

/edited out per academic honesty

Thanks in advance!

1
+100

Big problems start here char copy_line[] = ""; The char array copy_line is internally allocated for one byte. Regardless of whether you declare char* copy_line = ""; or char copy_line[] = "";, copy_line will be internally allocated for one byte.
You probably already know that char* copy_line = ""; will fail at strcpy(copy_line, line);. That's because any string literal (that is any string defined within double quotes) is stored in read-only memory and as such is immutable, it is essentially a const declaration.
You might also have tried char copy_line[strlen(line) + 1] = ""; But the compiler doesn't like that (error: variable-sized object may not be initialized).
You know that you have to copy line into something in order to use strtok. From man strcpy (emphasis added):

The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.

Therefore copy_line must first be allocated "large enough" to receive line. Any of
char copy_line[strlen(line) + 1]; or char* copy_line = malloc(strlen(line)+1); or
char* copy_line = calloc(strlen(line)+1,1); should work.

The seg fault is coming because copy_line is underallocated, and strcpy(copy_line,line) is corrupting some other variable's memory.

Once you get rid of the seg fault, you will be able to continue troubleshooting the function. Below are some of the things you are likely to encounter along the way, with possible corrections.


The 501 error:

This const char* identify = &request_str[0]; sets identify to "the address of request_str starting at index 0", so it is the whole string. It does not set identify to the single char in request_str[0]. This line
if (strcmp(identify, "/") != 0) evaluates to true for every request except root (ie '/'). There is no reason to declare another variable (identify). Other options, without a new variable, are
if (strncmp(request_str,"/",1) != 0) or if (request_str[0] != '/')


You will face a similar problem here if (strcmp(http_ver_str, "HTTP/1.1") != 0). Remember, from the spec, a properly formed request line is:

Per 3.1.1 of http://tools.ietf.org/html/rfc7230, a request-line is defined as

method SP request-target SP HTTP-version CRLF

wherein SP represents a single space ( ) and CRLF represents \r\n. None of method, request-target, and HTTP-version, meanwhile, may contain SP.

All things being equal, http_ver_str will contain the CRLF.


But wait! There's more! You will encounter problems here:

abs_path = path;

This is setting the address of abs_path to the address of the local variable path. 1) All local variables are "destroyed" when control returns to main. And 2) since abs_path is declared in main here char abs_path[LimitRequestLine + 1]; and thus acquires an address, main will always look for abs_path at that address. Better to use something like strcpy to update the contents of abs_path. The same applies to query_str. But beware, if you strcpy(a,b) when either a or b is NULL, it produces a runtime error. The relevance of that follows. You might want to leave query as is to get past check50/server1, because it is not tested until check50/server2.


Once these things are corrected, you are almost ready for check50/server1. The "strtok method" in parse very often produces two failures in check50/server1.

Two spaces after GET returns error code and Two spaces before HTTP/1.1 returns error code

From man strtok:

From the above description, it follows that a sequence of two or more contiguous delimiter bytes in the parsed string is considered to be a single delimiter,

According to the request-line spec, no valid request line will ever contain two spaces in a row. Think about how you could use strstr to find and "fail" that condition.


There are problems with the way you are building path and query_string. From the spec:

Per 5.3 of the same RFC, request-target, meanwhile, can take several forms, the only one of which your server needs to support is

absolute-path [ "?" query ]

absolute-path should not contain the '?' nor the query. You are going to have to rework this routine:

if (request_str != NULL)
{
   path = strtok(request_str, " ");
   query_str = strtok(NULL, "?");
   query_length = strlen(query);
}

Consider:

Based on the prior code, request_str will not contain a space. So path will be everything "between the two spaces", whether it is "/cat.jpg" or "/hello.php?name=Alice". Since the first call to strtok will "consume" all of request_str (because it doesn't find a space), query_str will always be NULL.

| improve this answer | |
  • Thank you so much! This is exactly what I was looking for. – SuperNovaCoder Jan 17 '17 at 13:59

You must log in to answer this question.

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