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;
}
}