0

I'm convinced that the issues lie within my parse and/or load function but can't seem to identify them. Maybe I'm incorrectly allocating memory?? I'm not sure. Can someone please help me out?

Here's my parse:

bool parse(const char* line, char* abs_path, char* query)
{
    // Extract 'method' string from 'line' string
int line_len = strlen(line);
char* temp = malloc(line_len);
char* method = malloc(line_len);
strcpy(temp, line);
strcpy(method, temp);
method = strtok(temp, " ");

// method spec
if((strlen(method)) != 3)
{
    error(405);
    return false;
}

if((strcasecmp(method, "get")) != 0)
{
    error(405);
    return false;
}    

// HTTP Version spec
char* version = strcasestr(line, "HTTP/1.1");
if(version == NULL)
{
    error(505);
    return false;
}

// .exe is not valid
char* exe_file = strcasestr(line, ".exe");
if(exe_file != NULL)
{
    error(501);
    return false;
}

// Extract 'request-target' string from 'line' string
char* temp1 = malloc(line_len);
char* req_target = malloc(line_len);
strcpy(temp1, line);
strcpy(req_target, temp1);

req_target = strtok(temp1, " ");
req_target = strtok(NULL, " ");

int tar_len = strlen(req_target) + 1;
char* temp2 = malloc(tar_len);
strcpy(temp2, req_target);

char* nul = malloc(1);
strcpy(nul, "\0");
strcat(temp2, nul);

// req_target spec
if(temp2[0] != '/')
{
    error(501);
    return false;
}

// filename must not have " 
for(int i = 0; i < line_len; i++)
{
    if (line[i] == '"')
    {
        error(400);
        return false;
    }
}

bool val = true;
while(true)
{
    // check if 'file is valid' spec
    char* valid_file = (strcasestr(abs_path, ".css"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".jpg"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".gif"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".ico"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".js"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".php"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".png"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }
    valid_file = (strcasestr(abs_path, ".html"));
    if(valid_file == NULL)
    {
        val = false;
    }
    else
    {
        val = true;
        break;
    }

    if(val == false)
    {
        error(404);
        return false;
    }
    break;
}

// CRCF spec
char* CRCF = strstr(line, "\r\n");
if(CRCF == NULL)
{
    error(400);
    return false;
}

 // set new abs_path
strcpy(abs_path, temp2);

// Extract 'query' string from 'line' string
char* temp3 = malloc(line_len);
char* the_query = malloc(line_len);
char* qry = query;
strcpy(temp3, line);
strcpy(the_query, temp3);

char* quest_m = strchr(the_query, '?');
if(quest_m != NULL)
{
    the_query = strtok(temp3, " ");
    the_query = strtok(NULL, "/");
    the_query = strtok(NULL, "?");
    the_query = strtok(NULL, " ");
}

// check if query exists
char* char_eq = strchr(the_query, '=');
if(char_eq != NULL)
{
    char* actual_query = malloc(line_len);
    strcpy(actual_query, "?");
    strcat(actual_query, the_query);
    strcat(actual_query, nul);
    strcpy(qry, actual_query);
}
else
{
    strcpy(qry, "\0");
}

    return true;
}

and then here's my Load:

bool load(FILE* file, BYTE** content, size_t* length)
{
    // don't go further if empty
    if(file == NULL) 
    {
         return false;
    }

BYTE *buffer;
size_t filelen;

// Jump to the end of the file
fseek(file, 0, SEEK_END);

// Get the current byte offset in the file      
filelen = ftell(file);             

// Jump back to the beginning of the file
rewind(file);                      

// Enough memory for file + \0
buffer = (BYTE *)malloc((filelen+1)*sizeof(BYTE)); 
fread(buffer, filelen, 1, file); // Read in the entire file
fclose(file); // Close the file

*length = filelen;
*content = buffer;

return true;
}
6
  • Please describe "not working" in more detail, perhaps with specific request-> result. Aug 26 '16 at 14:49
  • More specifically it's not passing the server2 check50 tests. And when I try a request it takes a while to load, then the ide prompts "something went wrong" Aug 28 '16 at 17:11
  • Sorry, this is still too broad. What request are you trying? And how, browser, curl? Where in the ide do you see "something went wrong"? A response to a curl request? From server? Have you tried gdb tips here, setting breakpoints at all the functions you wrote? That would perhaps narrow scope. Aug 28 '16 at 17:18
  • Well, how I've been doing things is: run ./server public then while it's listening, I right click on a file in my public directory and click preview (this worked for the staffs solution so that's why I did things this way). when I run that curl command it gives me 404 not found in the terminal window. I've checked out the gdb tips, thanks. But now I don't know how to stop the server so I can rerun gdb with my new breakpoints. To answer the other question, inside the ide there is a small red prompt message that drops down for a few seconds that says "something went wrong!"(when I preview stuff) Aug 30 '16 at 11:02
  • I just tried with the right-click>preview cat.html. It opened a browser tab that said "Starting apache50.... please wait..." and finally gave the "something went wrong" message. I don't think that method will test your server. You need to send a request to your server using a browser or curl. I am composing an answer now that will hopefully get you on your way again. The 404 from hello.html mentioned in your comment is a good lead. Aug 30 '16 at 11:42
0

First things first. Remove all that "lookup" code from parse. The spec (instructions) is very specific about what parse and lookup should do. It is almost always a bad idea to add things not in the specification, whether it's coursework or workwork. (that includes the exe_file area and the "val" while loop).

That "val" while loop explains why the curl request to hello.html returns a 404. Since abs_path is not populated yet (it's blank), any and all of the strcasecmp statements will return false.

This should get you in a better position to see what your server is really "doing".

I think your immediate goal should be to get hello.html to work from a curl request. You may have to get cozy with gdb, and that's a good thing.

You will face problems when hello.html calls hello.php. At a glance, I cannot say whether query is built correctly (that's what gdb is for). But I can tell that if there is a query, you will have a problem with abs_path. abs_path is defined in the spec as absolute-path [ "?" query ], so it should not include the '?' or anything following it.

Another problem you will face with hello.php is in the load function. php files are "pipes" as described in the spec. The functions fseek, ftell do not work on pipes. This load function may work on non-php files, but to pass all the checks in server2, you will want php's to work too. Consider the similarities of this function to the recover exercise in pset4. In that exercise you were asked to read file data and write it to another file. In this case, you're asked to read file data and store it in dynamically allocated memory (which is what your function is doing).

A final observation: beware of your malloc(line_len). That does not allocate a slot for the null-terminator.

The way to stop a server which is running in a terminal is "control c" (sometimes noted as ^C or ctrl-c).

This is a lot to digest. You might want to go back to the staff-version exercise in the instructions, without using the "right-click>preview". This will give you a good idea of what success looks like. Slow and steady. Build on small successes. You can do this.

Another note (!). In the instructions it says:

Toward the top-right corner of CS50 IDE, meanwhile, you should see your workspace’s "fully qualified domain name," an address of the form ide50-username.cs50.io, where username is your own username.

This has changed in more recent versions of the ide. If you do not see the address in the top right, click on the CS50 IDE tab in the top left and choose "Web Server" option.

3
  • Thank you so much! That helps a lot! One thing though, I knew about the Ctrl + C way to cancel the program, but I was probably unclear as to what i meant. When I want to run gdb with server.c it says, "Port 8080 already in use" and "stopping server". But it doesn't "stop". I retry the 'debug50 ./server public' and it just continues to give me that message. Aug 30 '16 at 13:02
  • Aha! I would try this: apache50 stop. It should produce some text that ends with * Stopping web server apache2 (the messages with [[ permission denied are just noise, can be ignored). If it does not, you should close all your terminal sessions and choose restart workspace from the CS50 IDE tab. When you session "comes back", run apache50 status. It should end with Apache is not running. Then you (should be!) able to start your server. Aug 30 '16 at 13:22
  • Thanks a lot!!! You're a sanity saver :) Aug 30 '16 at 13:26

You must log in to answer this question.

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