0

I tried to print the value of abs_path, it shows ok. But after running parse function in the main function(this line ---if (parse(line, abs_path, query)), I print the value and it turns to be null. Because of this, the server always redirect url. Could anyone explain the reason for me? Thanks.

// feature test macro requirements
#define _GNU_SOURCE
#define _XOPEN_SOURCE 700
#define _XOPEN_SOURCE_EXTENDED

// limits on an HTTP request's size, based on Apache's
// http://httpd.apache.org/docs/2.2/mod/core.html
#define LimitRequestFields 50
#define LimitRequestFieldSize 4094
#define LimitRequestLine 8190

// number of bytes for buffers
#define BYTES 512

// header files
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

// types
typedef char BYTE;

// prototypes
bool connected(void);
void error(unsigned short code);
void freedir(struct dirent** namelist, int n);
void handler(int signal);
char* htmlspecialchars(const char* s);
char* indexes(const char* path);
void interpret(const char* path, const char* query);
void list(const char* path);
bool load(FILE* file, BYTE** content, size_t* length);
const char* lookup(const char* path);
bool parse(const char* line, char* path, char* query);
const char* reason(unsigned short code);
void redirect(const char* uri);
bool request(char** message, size_t* length);
void respond(int code, const char* headers, const char* body, size_t length);
void start(short port, const char* path);
void stop(void);
void transfer(const char* path, const char* type);
char* urldecode(const char* s);

// server's root
char* root = NULL;

// file descriptor for sockets
int cfd = -1, sfd = -1;

// flag indicating whether control-c has been heard
bool signaled = false;

int main(int argc, char* argv[])
{
    // a global variable defined in errno.h that's "set by system 
    // calls and some library functions [to a nonzero value]
    // in the event of an error to indicate what went wrong"
    errno = 0;

    // default to port 8080
    int port = 8080;

    // usage
    const char* usage = "Usage: server [-p port] /path/to/root";

    // parse command-line arguments
    int opt;
    while ((opt = getopt(argc, argv, "hp:")) != -1)
    {
        switch (opt)
        {
            // -h
            case 'h':
                printf("%s\n", usage);
                return 0;

            // -p port
            case 'p':
                port = atoi(optarg);
                break;
        }
    }

    // ensure port is a non-negative short and path to server's root is specified
    if (port < 0 || port > SHRT_MAX || argv[optind] == NULL || strlen(argv[optind]) == 0)
    {
        // announce usage
        printf("%s\n", usage);

        // return 2 just like bash's builtins
        return 2;
    }

    // start server
    start(port, argv[optind]);

    // listen for SIGINT (aka control-c)
    struct sigaction act;
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGINT, &act, NULL);

    // a message and its length
    char* message = NULL;
    size_t length = 0;

    // path requested
    char* path = NULL;

    // accept connections one at a time
    while (true)
    {
        // free last path, if any
        if (path != NULL)
        {
            free(path);
            path = NULL;
        }

        // free last message, if any
        if (message != NULL)
        {
            free(message);
            message = NULL;
        }
        length = 0;

        // close last client's socket, if any
        if (cfd != -1)
        {
            close(cfd);
            cfd = -1;
        }

        // check for control-c
        if (signaled)
        {
            stop();
        }

        // check whether client has connected
        if (connected())
        {
            // check for request
            if (request(&message, &length))
            {
                // extract message's request-line
                // http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
                const char* haystack = message;
                const char* needle = strstr(haystack, "\r\n");
                if (needle == NULL)
                {
                    error(500);
                    continue;
                }
                char line[needle - haystack + 2 + 1];
                strncpy(line, haystack, needle - haystack + 2);
                line[needle - haystack + 2] = '\0';

                // log request-line
                printf("%s", line);

                // parse request-line
                char abs_path[LimitRequestLine + 1];
                char query[LimitRequestLine + 1];
                if (parse(line, abs_path, query))
                {
                    printf("abs_path%s\n",abs_path);
                    // URL-decode absolute-path
                    char* p = urldecode(abs_path);
                    if (p == NULL)
                    {
                        error(500);
                        continue;
                    }

                    // resolve absolute-path to local path
                    path = malloc(strlen(root) + strlen(p) + 1);
                    if (path == NULL)
                    {
                        error(500);
                        continue;
                    }
                    strcpy(path, root);
                    strcat(path, p);
                    free(p);

                    // ensure path exists
                    if (access(path, F_OK) == -1)
                    {
                        error(404);
                        continue;
                    }

                    // if path to directory
                    struct stat sb;
                    if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode))
                    {
                        // redirect from absolute-path to absolute-path/
                        printf("abs_path%s\n",abs_path);

                        if (abs_path[strlen(abs_path) - 1] != '/')
                        {
                            char uri[strlen(abs_path) + 1 + 1];
                            strcpy(uri, abs_path);
                            strcat(uri, "/");
                            redirect(uri);
                            continue;
                        }

                        // use path/index.php or path/index.html, if present, instead of directory's path
                        char* index = indexes(path);
                        if (index != NULL)
                        {
                            free(path);
                            path = index;
                        }

                        // list contents of directory
                        else
                        {
                            list(path);
                            continue;
                        }
                    }

                    // look up MIME type for file at path
                    const char* type = lookup(path);
                    if (type == NULL)
                    {
                        error(501);
                        continue;
                    }

                    // interpret PHP script at path
                    if (strcasecmp("text/x-php", type) == 0)
                    {
                        interpret(path, query);
                    }

                    // transfer file at path
                    else
                    {
                        transfer(path, type);
                    }
                }
            }
        }
    }
}



bool parse(const char* line, char* abs_path, char* query)
{
    char* method =NULL;
    char* request_target = NULL;
    char* http_version = NULL;
    char* absolute_path = NULL;
    const char* haystack1 = line;
    char* needle1 = strstr(haystack1," ");
    if(needle1 != NULL)
    {
        method = malloc(needle1 - line + 1);
        strncpy(method,line,needle1 - line );
        method[needle1-line] = '\0';
        printf("method %s\n",method);
        if (strncmp(method,"GET", 4) != 0)
        {
            free(method);
            error(405);
            return false;
        }

    }

    char* needle2 = strstr(haystack1, "\r\n");
    char* newline = NULL;
    if (needle2 != NULL)
    {
        newline = malloc(strlen(line) - 3);
        strcpy(newline,line+4);
        newline[strlen(line) - 4] = '\0';
        printf("newline %s\n",newline);
    }
    else
    {
        return false;
    }
    char* needle3 = strstr(newline," ");
    request_target = malloc(needle3 - newline + 1);
    strncpy(request_target, newline, needle3-newline);
    request_target[needle3-newline] = '\0';
    printf("request_target %s\n",request_target);
    if(request_target[0] !='/')
    {
        free(request_target);
        free(newline);
        free(method);
        error(501);
        return false;
    }
    if(strstr(request_target, "\"") != NULL)
    {
        free(request_target);
        free(newline);
        free(method);
        error(400);
        return false;
    }
    if(strstr(request_target,"?") == NULL)
    {
        query = malloc(1);
        absolute_path = malloc(strlen(request_target)+1);
        strcpy(absolute_path, request_target);
        absolute_path[strlen(request_target)] = '\0';
        query[0] = '\0';
        printf("absolute_path %s\n",absolute_path);
    }
    else
    {
        char* needle4 = strstr(request_target,"?");
        query = malloc(needle3 - needle4 + 1 - strlen(absolute_path));
        absolute_path = malloc(needle4 - request_target +1);
        strncpy(absolute_path, request_target, needle4-request_target);
        absolute_path[needle4 -request_target] = '\0';
        printf("absolute_path %s\n",absolute_path);
        strncpy(query, request_target+strlen(absolute_path), needle3 - needle4 + 1 - strlen(absolute_path));
        query[needle3 - needle4 - strlen(absolute_path)] = '\0';
        printf("query%s \n",query);
    }
    char* needle5 = strstr(newline,"\r\n");
    if(needle5 == NULL)
    {
        free(request_target);
        free(newline);
        free(method);
        free(absolute_path);
        free(query);
        return false;
    }
    else
    {
        http_version = malloc(needle5 - needle3 );
        strncpy(http_version,newline+strlen(request_target)+1, needle5 - needle3-1);
        http_version[needle5 - needle3-1 ] = '\0';
        printf("http_version %s\n",http_version);
    }
    if (strcmp(http_version,"HTTP/1.1")==0)
    {
        abs_path = malloc(strlen(absolute_path)+1);
        strcpy(abs_path,absolute_path);
        abs_path[strlen(absolute_path)] = '\0';
        free(request_target);
        free(newline);
        free(method);
        free(http_version);
        free(absolute_path);
        printf("abs_path%s\n",abs_path);
        return true;
    }
    else{
        free(request_target);
        free(newline);
        free(method);
        free(http_version);
        free(absolute_path);
        free(query);
        error(505);
        return false;       
    }
}

1 Answer 1

0

A quick scan of the posted code revealed this: abs_path = malloc(strlen(absolute_path)+1); That gives abs_path a new address locally in the parse function. When control returns to main, it will be looking for abs_path at the address it got when it was declared here
char abs_path[LimitRequestLine + 1];. The same fate befalls query here query = malloc(1);. That is the reason abs_path and query are passed to parse as arguments - so the computed values will be stored at the addresses assigned in main.

1
  • Thanks. It solves the problem.
    – Charlotte
    Commented Dec 2, 2016 at 23:18

You must log in to answer this question.

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