0

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

1 Answer 1

1

This declaration char* request = ""; basically makes request a const char*, and as such is immutable. You should not "set" it to "", rather it needs to have some memory allocated before anything is copied into it.

Similarly, this line requestHttpAndTail[i] = '\0'; fails because requeHttpAndTail is a pointer into line's memory, line is a const char* and thus immutable.

And beware, this abs_path = request; is a slippery slope. Assuming request is a locally allocated variable, its memory will be destroyed when program control returns to main, leaving abs_path, well, not what you expect.

Notice how abs_path and query are declared in server. You would create a much closer repro case if p and q were declared similarly. (Besides the fact that as written, they are immutable).

1
  • Ok, I think I got it. I set the tests to char arrays, like in the server, made sure I calloc-ed some memory for the pointers, and addressed the slippery slope issue you mentioned. It seems to be working properly now. I may be back later, but this was a huge help. Thank you. Commented Oct 29, 2016 at 22:47

You must log in to answer this question.

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