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
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_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.
const char* identify = &request_str; 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. 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 != '/')
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);
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.