Last active
December 20, 2015 09:49
-
-
Save guregu/6110999 to your computer and use it in GitHub Desktop.
小さなWebサーバ ・ Unix系のOSで実行してください ・ デフォルトはhttp://localhost:8888からアクセスできます
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* * * * * * * * * * * * | |
* シンプルなHTTPサーバ | |
* Gregory Scott Roseberry | |
* 1M100407-6 | |
* * * * * * * * * * * */ | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
#define DEFAULT_PORT (8888) | |
#define BUFFER_SIZE (1024) | |
void idx(int); | |
void not_found(int); | |
void not_supported(int); | |
void run_cmd(int, char*); | |
ssize_t read_line(int, void*, size_t); | |
int main(int argc, char* argv[]) { | |
int listener; | |
int client; | |
short int port; | |
struct sockaddr_in server_address; | |
char buffer[BUFFER_SIZE]; | |
if (argc == 2) { | |
port = atoi(argv[1]); | |
} else { | |
port = DEFAULT_PORT; | |
} | |
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
fprintf(stderr, "Couldn't create listener socket.\n"); | |
exit(-1); | |
} | |
memset(&server_address, 0, sizeof(server_address)); | |
server_address.sin_family = AF_INET; | |
server_address.sin_addr.s_addr = htonl(INADDR_ANY); | |
server_address.sin_port = htons(port); | |
if (bind(listener, (struct sockaddr*) &server_address, sizeof(server_address)) < 0) { | |
fprintf(stderr, "Couldn't bind().\n"); | |
exit(-1); | |
} | |
if (listen(listener, 1024)) { | |
fprintf(stderr, "Couldn't listen().\n"); | |
exit(-1); | |
} | |
while(1) { | |
if ((client = accept(listener, NULL, NULL)) < 0) { | |
fprintf(stderr, "Couldn't accept().\n"); | |
exit(-1); | |
} | |
read_line(client, buffer, BUFFER_SIZE-1); | |
char* token; | |
token = strtok(buffer, " "); | |
if (strcmp(token, "GET") == 0) { | |
token = strtok(NULL, " "); | |
if (token != NULL) { | |
if (strcmp(token, "/") == 0) { | |
idx(client); | |
} else if (strcmp(token, "/ps") == 0) { | |
run_cmd(client, "ps aux"); | |
} else if (strcmp(token, "/emacs") == 0) { | |
run_cmd(client, "ps aux | grep emacs"); | |
} else if (strcmp(token, "/w") == 0) { | |
run_cmd(client, "w"); | |
} else if (strcmp(token, "/finger") == 0) { | |
run_cmd(client, "finger"); | |
} else if (strcmp(token, "/uptime") == 0) { | |
run_cmd(client, "uptime"); | |
} else if (strcmp(token, "/uname") == 0) { | |
run_cmd(client, "uname -a"); | |
} else if (strcmp(token, "/netstat") == 0) { | |
run_cmd(client, "netstat -a"); | |
} else if (strcmp(token, "/df") == 0) { | |
run_cmd(client, "df -H"); | |
} else { | |
not_found(client); | |
} | |
} | |
} else { | |
not_supported(client); | |
} | |
if (close(client) < 0) { | |
fprintf(stderr, "Couldn't close().\n"); | |
exit(-1); | |
} | |
} | |
} | |
void idx(int client) { | |
char buf[BUFFER_SIZE]; | |
sprintf(buf, "HTTP/1.0 200 OK\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Content-type: text/html\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<html><head><title>小さなWebサーバ</title></head>"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<body><h2>小さなWebサーバ</h2><ul>"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/ps", "プロセス"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/emacs", "プロセス(emacsのみ)"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/w", "ユーザー"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/finger", "finger"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/uptime", "uptime"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/uname", "サーバのOS等"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/netstat", "netstat"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<li><a href=\"%s\">%s</a></li>", "/df", "HDDの使用状況"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "</li></body></html>"); | |
send(client, buf, strlen(buf), 0); | |
} | |
void run_cmd(int client, char* cmd) { | |
FILE *fp; | |
char buf[BUFFER_SIZE]; | |
fp = popen(cmd, "r"); | |
if (fp == NULL) { | |
sprintf(buf, "HTTP/1.0 200 OK\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Content-type: text/html\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Failed to run command. :(\r\n" ); | |
} else { | |
sprintf(buf, "HTTP/1.0 200 OK\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Content-type: text/html\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<html><head><title>%s</title></head>", cmd); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "<body><h2>%s</h2><pre>", cmd); | |
send(client, buf, strlen(buf), 0); | |
while (fgets(buf, sizeof(buf) - 1, fp) != NULL) { | |
send(client, buf, strlen(buf), 0); | |
} | |
sprintf(buf, "</pre></body></html>"); | |
send(client, buf, strlen(buf), 0); | |
pclose(fp); | |
} | |
} | |
void not_found(int client) { | |
char buf[BUFFER_SIZE]; | |
sprintf(buf, "HTTP/1.0 404 Not Found\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Content-type: text/html\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "No such page exists.\r\n"); | |
send(client, buf, strlen(buf), 0); | |
} | |
void not_supported(int client) { | |
char buf[BUFFER_SIZE]; | |
sprintf(buf, "HTTP/1.0 405 Method Not Allowed\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "Content-type: text/html\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "\r\n"); | |
send(client, buf, strlen(buf), 0); | |
sprintf(buf, "That method is not supported.\r\n"); | |
send(client, buf, strlen(buf), 0); | |
} | |
// W. Richard Stevensさんの「UNIX Network Programming」から拾った関数です | |
ssize_t read_line(int sockd, void* vptr, size_t maxlen) { | |
ssize_t n, rc; | |
char c, *buffer; | |
buffer = vptr; | |
for ( n = 1; n < maxlen; n++ ) { | |
if ( (rc = read(sockd, &c, 1)) == 1 ) { | |
*buffer++ = c; | |
if ( c == '\n' ) | |
break; | |
} | |
else if ( rc == 0 ) { | |
if ( n == 1 ) | |
return 0; | |
else | |
break; | |
} | |
else { | |
if ( errno == EINTR ) | |
continue; | |
return -1; | |
} | |
} | |
*buffer = 0; | |
return n; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment