Skip to content

Instantly share code, notes, and snippets.

@guregu
Last active December 20, 2015 09:49
Show Gist options
  • Save guregu/6110999 to your computer and use it in GitHub Desktop.
Save guregu/6110999 to your computer and use it in GitHub Desktop.
小さなWebサーバ ・ Unix系のOSで実行してください ・ デフォルトはhttp://localhost:8888からアクセスできます
/* * * * * * * * * * * *
* シンプルな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