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.