I've been trying to test each part of the server pset as I go along, and so I copied, pasted, and wrote a little test program to make sure that the pieces are working individually. When I tried testing parse, I found a few bugs, but now I'm stuck on a Segmentation Fault.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
bool parse(const char* line, char* abs_path, char* query);
const char* reason(unsigned short code);
void error(unsigned short code);
int main (void)
{
char* p = "";
char* q = "";
char* line = "GET \\home HTTP/1.1\r\n";
parse(line, p, q);
printf("Path: %s Query: %s\n", p, q);
}
bool parse(const char* line, char* abs_path, char* query)
{
// checking to make sure that line has the proper format with spaces and such
char* requestHttpAndTail = strchr(line, ' ');
requestHttpAndTail = &requestHttpAndTail[1]; //gets rid of the space up front
char* httpAndTail = strchr(requestHttpAndTail, ' ');
httpAndTail = &httpAndTail[1]; //gets rid of the space up front
char* anyMoreSpaces = strchr(httpAndTail, ' ');
char* tail = strchr(httpAndTail, '\r');
if (requestHttpAndTail == NULL || httpAndTail == NULL) // checking for two spaces
{
error(400);
return false;
}
if ((strcasecmp(tail, "\r\n")) != 0) // checking to make sure it ends with \r\n
{
error(400);
return false;
}
if(anyMoreSpaces != NULL) // checking for not more than two spaces
{
error(400);
return false;
}
//checking to make sure the method is GET
if (strncmp(line, "GET", 3) != 0)
{
error(405);
return false;
}
//checking to make sure that HTTP-version is HTTP/1.1 (followed by \r\n)
if (strcasecmp(httpAndTail, "HTTP/1.1\r\n") != 0)
{
error(505);
return false;
}
//checking request target last because that takes multiple steps
if (requestHttpAndTail[0] != '\\') //first character is a space, so second character must be /
{
error(501);
return false;
}
for (int i = 0; i < strlen(requestHttpAndTail); i++) //exit if any character is "
{
if (requestHttpAndTail[i] == '\"')
{
error(400);
return false;
}
}
//ok, getting the requestHttpAndTail variable to just the request
char* request = "";
bool isQuery = false;
for (int i = 0; i < strlen(requestHttpAndTail); i++)
{
if (requestHttpAndTail[i] == '?')
{
isQuery = true;
}
if (requestHttpAndTail[i] == ' ') //find the space
{
strncpy(request, requestHttpAndTail, i); //seg faulted here
break;
}
}
//check to see if there was a query, deals with it if so, and then sets the two pointers
if (isQuery)
{
char* shortRequest = "";
for (int i = 0; i < strlen(request); i++)
{
if (request[i] == '?')
{
strcpy(query, &request[i + 1]);
strncpy(shortRequest, request, i); //tried this: request[i] = '\0';
abs_path = shortRequest;
break;
}
}
}
else
{
query = "";
abs_path = request;
}
//error(501);
return true;
}
//from the server program
const char* reason(unsigned short code)
{
switch (code)
{
case 200: return "OK";
case 301: return "Moved Permanently";
case 400: return "Bad Request";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 414: return "Request-URI Too Long";
case 418: return "I'm a teapot";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 505: return "HTTP Version Not Supported";
default: return NULL;
}
}
//from the server program
void error(unsigned short code)
{
// determine code's reason-phrase
const char* phrase = reason(code);
printf("Error %d: %s\n", code, phrase);
}
I ran through gdb and the segfault is happening at line 84, where it says:
strncpy(request, requestHttpAndTail, i);
I marked this line with a comment as well.
I had previously tried this approach, just trying to insert a null terminator into the string to cut it off, but that also gave me a segfault:
requestHttpAndTail[i] = '\0';
I'm at a loss here. Any help that folks could offer would be greatly appreciated.
Thanks,
-Brian