?? tmhttpd.c
字號:
now = time( (time_t*) 0 );
strftime( timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime( &now ) );
memset(buf, 0, strlen(buf));
sprintf(buf, "Date: %s\r\n", timebuf);
strcat(buf_all, buf);
if (extra_header != (char*)0){
memset(buf, 0, strlen(buf));
sprintf(buf, "%s\r\n", extra_header);
strcat(buf_all, buf);
}
if (mime_type != (char*)0){
memset(buf, 0, strlen(buf));
sprintf(buf, "Content-Type: %s\r\n", mime_type);
strcat(buf_all, buf);
}
if (length >= 0){
memset(buf, 0, strlen(buf));
sprintf(buf, "Content-Length: %lld\r\n", (int64_t)length);
strcat(buf_all, buf);
}
if (mod != (time_t) -1 ){
memset(buf, 0, strlen(buf));
strftime( timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime( &mod ) );
sprintf(buf, "Last-Modified: %s\r\n", timebuf );
strcat(buf_all, buf);
}
memset(buf, 0, strlen(buf));
sprintf(buf, "Connection: close\r\n\r\n");
strcat(buf_all, buf);
/* Debug message */
if ( g_is_debug ){
fprintf(stderr, "[ Response ]\n");
fprintf(stderr, "%s", buf_all);
}
/* Write http header to client socket */
write(client_sock, buf_all, strlen(buf_all));
return 0;
}
/**
* Send http error message
*
* @param int status
* @param char* title
* @param char* extra
*/
static int SendError(int client_sock, int status, char *title, char *extra_header, char *text ){
char buf[BUFFER_SIZE], buf_all[REQUEST_MAX_SIZE];
/* Send http header */
SendHeaders( client_sock, status, title, extra_header, "text/html", -1, -1 );
/* Send html page */
memset(buf, 0, strlen(buf));
sprintf(buf, "<html>\n<head>\n<title>%d %s - %s</title>\n</head>\n<body>\n<h2>%d %s</h2>\n", status, title, SERVER_NAME, status, title);
strcat(buf_all, buf);
memset(buf, 0, strlen(buf));
sprintf(buf, "%s\n", text);
strcat(buf_all, buf);
memset(buf, 0, strlen(buf));
sprintf(buf, "\n<br /><br /><hr />\n<address>%s</address>\n</body>\n</html>\n", SERVER_NAME);
strcat(buf_all, buf);
/* Write client socket */
write(client_sock, buf_all, strlen(buf_all));
exit(0);
}
/**
* Send file contents to client
*
*/
static int SendFile( int client_sock, char *filename, char *pathinfo ){
char buf[128], contents[8192], mime_type[64];
int fd;
size_t file_size;
/* Get mime type & send http header information */
mime_content_type(filename, mime_type);
SendHeaders( client_sock, 200, "OK", "", mime_type, filesize(filename), 0);
/* Open file */
if ( (fd = open(filename, O_RDONLY)) == -1 ){
memset(buf, '\0', sizeof(buf));
sprintf(buf, "Something unexpected went wrong read file %s.", pathinfo);
SendError( client_sock, 500, "Internal Server Error", "", buf);
}
/* Read static file write to client socket (File size less 8192 bytes) */
file_size = filesize(filename);
if ( file_size < 8192){
read(fd, contents, 8192);
write( client_sock, contents, file_size );
} else {
while ( read(fd, contents, 8192) > 0 ){
write( client_sock, contents, 8192 );
memset(contents, '\0', sizeof(contents));
}
}
/* Close file descriptor */
close( fd );
/* Debug message */
if (g_is_debug){
printf("request filename: %s\n", filename);
printf("request pathinfo: %s\n", pathinfo);
}
return 0;
}
/**
* Send directory index list to client
*
*/
static int SendDirectory( int client_sock, char *path, char *pathinfo ){
size_t file_size;
char msg[128], buf[10240], tmp[1024], tmp_path[1024];
DIR *dp;
struct dirent *node;
/* Open directory */
if ( (dp = opendir(path)) == NULL ){
memset(buf, 0, sizeof(msg));
sprintf(msg, "Something unexpected went wrong browse directory %s.", pathinfo);
SendError( client_sock, 500, "Internal Server Error", "", msg);
}
/* Check pathinfo is valid */
memset(tmp_path, 0, sizeof(tmp_path));
substr(pathinfo, -1, 1, tmp_path);
if ( strcmp(tmp_path, "/") == 0){
memset(tmp_path, 0, sizeof(tmp_path));
strcpy(tmp_path, pathinfo);
} else {
memset(tmp_path, 0, sizeof(tmp_path));
strcpy(tmp_path, pathinfo);
strcat(tmp_path, "/");
}
/* Fetch directory list */
sprintf( tmp, "<html>\n<head>\n<title>Browse directory %s - %s</title>\n</head>\n<body><h3>Directory %s</h3>\n<hr />\n<ul>\n", pathinfo, SERVER_NAME, pathinfo );
strcat(buf, tmp);
while ( (node = readdir(dp)) != NULL){
if ( strcmp(node->d_name, ".") != 0){
memset(tmp, 0, sizeof(tmp));
sprintf(tmp, "\t<li><a href=\"%s%s\">%s</a></li>\n", tmp_path, node->d_name, node->d_name);
strcat(buf, tmp);
}
}
memset(tmp, 0, sizeof(tmp));
sprintf(tmp, "\n</ul>\n<br /><hr />\n<address>%s</address>\n</body>\n</html>\n", SERVER_NAME);
strcat(buf, tmp);
file_size = strlen(buf);
SendHeaders( client_sock, 200, "OK", "", "text/html", file_size, 0 );
write( client_sock, buf, file_size );
return 0;
}
/**
* Process request
*
*/
static int ProcRequest( int client_sock, struct sockaddr_in client_addr, struct st_request_info request_info ){
char buf[128];
/* File is exist or has access permission */
if ( !file_exists( request_info.physical_path ) ){
memset(buf, 0, sizeof(buf));
sprintf(buf, "File %s not found.", request_info.pathinfo);
SendError( client_sock, 404, "Not Found", "", buf);
}
if ( access(request_info.physical_path, R_OK) != 0 ){
memset(buf, 0, sizeof(buf));
sprintf(buf, "File %s is protected.", request_info.pathinfo);
SendError( client_sock, 403, "Forbidden", "", buf);
}
/* Check target is regular file or directory */
if ( is_file(request_info.physical_path) == 1 ){
SendFile( client_sock, request_info.physical_path, request_info.pathinfo );
} else if ( is_dir(request_info.physical_path) == 1 ){
/* Is a directory choose browse dir list */
if ( g_is_browse ){
SendDirectory( client_sock, request_info.physical_path, request_info.pathinfo );
} else {
memset(buf, 0, sizeof(buf));
sprintf(buf, "File %s is protected.", request_info.pathinfo);
SendError( client_sock, 403, "Forbidden", "", buf);
}
} else {
memset(buf, 0, sizeof(buf));
sprintf(buf, "File %s is protected.", request_info.pathinfo);
SendError( client_sock, 403, "Forbidden", "", buf);
}
return 0;
}
/**
* Parse client request
*
*/
static int ParseRequest( int client_sock, struct sockaddr_in client_addr, char *req ){
char **buf, **method_buf, **query_buf, currtime[32], cwd[1024], tmp_path[1536], pathinfo[512], path[256], file[256], log[1024];
int line_total, method_total, query_total, i;
struct st_request_info request_info;
/* Split client request */
getdate(currtime);
explode(req, '\n', &buf, &line_total);
/* Print log message */
memset(log, 0, sizeof(log));
sprintf(log, "[%s] %s %s\n", currtime, inet_ntoa(client_addr.sin_addr), buf[0]);
WriteLog(log);
/* Check request is empty */
if (strcmp(buf[0], "\n") == 0 || strcmp(buf[0], "\r\n") == 0){
SendError( client_sock, 400, "Bad Request", "", "Can't parse request." );
}
/* Check method is implement */
explode(buf[0], ' ', &method_buf, &method_total);
if ( strcmp( strtolower(method_buf[0]), "get") != 0 && strcmp( strtolower(method_buf[0]), "head") != 0 ){
SendError( client_sock, 501, "Not Implemented", "", "That method is not implemented." );
}
explode(method_buf[1], '?', &query_buf, &query_total);
/* Make request data */
getcwd(cwd, sizeof(cwd));
strcpy(pathinfo, query_buf[0]);
substr(query_buf[0], 0, strrpos(pathinfo, '/')+1, path);
substr(query_buf[0], strrpos(pathinfo, '/')+1, 0, file);
/* Pad request struct */
memset(&request_info, 0, sizeof(request_info));
strcat(cwd, pathinfo);
request_info.method = method_buf[0];
request_info.pathinfo = pathinfo;
request_info.query = (query_total == 2 ? query_buf[1] : "");
request_info.protocal = strtolower(method_buf[2]);
request_info.path = path;
request_info.file = file;
request_info.physical_path = cwd;
/* Is a directory pad default index page */
memset(tmp_path, 0, sizeof(tmp_path));
strcpy(tmp_path, cwd);
if ( is_dir(tmp_path) ){
strcat(tmp_path, g_dir_index);
if ( file_exists(tmp_path) ){
request_info.physical_path = tmp_path;
}
}
/* Debug message */
if ( g_is_debug ){
fprintf(stderr, "[ Request ]\n");
for(i=0; i<line_total; i++){
fprintf(stderr, "%s\n", buf[i]);
}
}
/* Process client request */
ProcRequest( client_sock, client_addr, request_info );
return 0;
}
/**
* Handle a client
*
*/
static void HandleClient( int client_sock, struct sockaddr_in client_addr ){
char buf[REQUEST_MAX_SIZE];
if ( read(client_sock, buf, REQUEST_MAX_SIZE) < 0){
SendError( client_sock, 500, "Internal Server Error", "", "Client request not success." );
die("read sock");
}
ParseRequest( client_sock, client_addr, buf );
close(client_sock);
exit(0);
}
/**
* Initialize server socket listen
*
*/
static void InitServerListen( unsigned int port, unsigned int max_client ){
int serversock, clientsock;
struct sockaddr_in server_addr, client_addr;
char currtime[32];
/* Create the TCP socket */
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
die("Failed to create socket");
}
/* Construct the server sockaddr_in structure */
memset(&server_addr, 0, sizeof(server_addr)); /* Clear struct */
server_addr.sin_family = AF_INET; /* Internet/IP */
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Incoming addr */
server_addr.sin_port = htons(port); /* server port */
/* Bind the server socket */
if (bind(serversock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0){
die("Failed to bind the server socket");
}
/* Listen on the server socket */
if (listen(serversock, max_client) < 0){
die("Failed to listen on server socket");
}
/* Print listening message */
getdate(currtime);
fprintf(stdout, "[%s] Start server listening at port %d ...\n", currtime, port);
fprintf(stdout, "[%s] Waiting client connection ...\n", currtime);
/* Run until cancelled */
while (1){
unsigned int clientlen = sizeof(client_addr);
memset(currtime, 0, sizeof(currtime));
getdate(currtime);
/* Wait for client connection */
if ((clientsock = accept(serversock, (struct sockaddr *) &client_addr, &clientlen)) < 0){
die("Failed to accept client connection");
}
/* Use child process new connection */
if ( fork() == 0 ){
HandleClient(clientsock, client_addr);
} else {
wait(NULL);
}
/* Not use close socket connection */
close(clientsock);
}
}
/**
* Parse cmd options
*
*/
static int ParseOptions( int argc, char *argv[] ){
int opt;
struct option longopts[] = {
{ "is-debug", 0, NULL, 'D' },
{ "is-daemon", 0, NULL, 'd' },
{ "port", 1, NULL, 'p' },
{ "max-client", 1, NULL, 'm' },
{ "is-log", 0, NULL, 'L' },
{ "log-path", 1, NULL, 'l' },
{ "is-browse", 0, NULL, 'b' },
{ "doc-root", 1, NULL, 'r' },
{ "dir-index", 1, NULL, 'i' },
{ "help", 0, NULL, 'h' },
{ 0, 0, 0, 0 }
};
/* Parse every options */
while ( (opt = getopt_long(argc, argv, ":Ddp:m:Ll:br:i:h", longopts, NULL)) != -1){
switch (opt){
case 'h':
Usage(argv[0]);
return(-1);
break;
case 'D': g_is_debug = 1; break;
case 'd': g_is_daemon = 1; break;
case 'p':
g_port = atoi(optarg);
if ( g_port < 1 || g_port > 65535 ){
fprintf(stderr, "Options -p,--port error: input port number %s invalid, must between 1 - 65535.\n\n", optarg);
return(-1);
}
break;
case 'm':
g_max_client = atoi(optarg);
if ( !isdigit(g_max_client) ){
fprintf(stderr, "Options -m,--max-client error: input clients %s invalid, must number, proposal between 32 - 2048.\n\n", optarg);
return(-1);
}
break;
case 'L': g_is_log = 1; break;
case 'l':
strcpy(g_log_path, optarg);
if ( !file_exists(g_log_path) || !is_dir(g_log_path) ){
fprintf(stderr, "Options -l,--log-path error: input path %s not exist or not a directory.\n\n", optarg);
return(-1);
}
break;
case 'b': g_is_browse = 1; break;
case 'r':
strcpy(g_doc_root, optarg);
if ( !file_exists(g_doc_root) || !is_dir(g_doc_root) ){
fprintf(stderr, "Options -l,--log-path error: input path %s not exist or not a directory.\n\n", optarg);
return(-1);
}
break;
case 'i':
strcpy(g_dir_index, optarg);
break;
}
}
return(0);
}
/********************************
*
* Http Server running
*
********************************/
/**
* Main function
*
*/
int main( int argc, char *argv[] ){
/* Parse cli input options */
if ( argc > 1 ){
if ( ParseOptions( argc, argv ) != 0 ){
exit(-1);
}
}
/* Set work directory */
chdir(g_doc_root);
/* Set is daemon mode run */
if ( g_is_daemon ){
pid_t pid;
if ( (pid = fork()) < 0 ){
die("daemon fork error");
} else if ( pid != 0){
exit(1);
}
}
/* Debug mode out configure information */
if ( g_is_debug ){
PrintConfig();
}
/* Start server listen */
InitServerListen( g_port, g_max_client );
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -