Skip to content

Instantly share code, notes, and snippets.

@pikhq
Created February 21, 2014 02:46
Show Gist options
  • Save pikhq/9127855 to your computer and use it in GitHub Desktop.
Save pikhq/9127855 to your computer and use it in GitHub Desktop.
#define _XOPEN_SOURCE 700
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <spawn.h>
#include <string.h>
extern char **environ;
static void my_perror(char *argv0, char *msg)
{
char *err = strerror(errno);
write(2, argv0, strlen(argv0));
write(2, ": ", 2);
write(2, msg, strlen(msg));
write(2, ": ", 2);
write(2, err, strlen(err));
write(2, "\n", 1);
}
int main(int argc, char **argv)
{
int sockfd;
char *port = 0;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE
};
struct addrinfo *servinfo, *p;
int rv;
int opt;
while((opt = getopt(argc, argv, "tup:")) != -1) {
switch(opt) {
case 'p':
port = optarg;
break;
case 't':
hints.ai_socktype = SOCK_STREAM;
break;
case 'u':
hints.ai_socktype = SOCK_DGRAM;
break;
default:
return 1;
}
}
if(optind >= argc) {
write(2, argv[0], strlen(argv[0]));
write(2, ": expected argument\n", strlen(": expected argument\n"));
return 1;
}
if(!port) {
write(2, argv[0], strlen(argv[0]));
write(2, ": expected port\n", strlen(": expected port\n"));
return 1;
}
if((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) {
const char *err = gai_strerror(rv);
write(2, argv[0], strlen(argv[0]));
write(2, ": getaddrinfo: ", strlen(": getaddrinfo :"));
write(2, err, strlen(err));
write(2, "\n", 1);
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
int flags = 0;
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
my_perror(argv[0], "socket");
continue;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) {
my_perror(argv[0], "setsockopt");
close(sockfd);
continue;
}
if(fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
my_perror(argv[0], "fcntl");
close(sockfd);
continue;
}
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
my_perror(argv[0], "bind");
close(sockfd);
continue;
}
break;
}
if(!p) return 1;
if(listen(sockfd, 20) == -1) {
my_perror(argv[0], "listen");
return 1;
}
close(0);
close(1);
signal(SIGCHLD, SIG_IGN);
while(1) {
if(accept(sockfd, 0, 0) == -1) {
my_perror(argv[0], "accept");
continue;
}
if(dup(0) == -1) {
my_perror(argv[0], "dup");
close(0);
continue;
}
if(posix_spawnp(&(int){0}, argv[optind], 0, 0, &argv[optind], environ)) {
my_perror(argv[0], "posix_spawnp");
close(0);
close(1);
continue;
}
close(0);
close(1);
}
}
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
static void http_error(int code)
{
printf("HTTP/1.0 %d Error\r\n"
"Content-type: text/plain; charset=UTF-8\r\n"
"\r\n"
"%d error\r\n", code, code);
exit(0);
}
static char *fgetline(char *s, int len, FILE *f)
{
char *ret;
ret = fgets(s, len, f);
if(!ret) return ret;
if(strlen(s) == len - 1 && s[len-1] != '\n') {
while(!feof(f) && getc(f) != '\n');
}
for(; *s; s++)
if(*s == '\r' || *s == '\n') {
*s = '\0';
break;
}
return ret;
}
int main(int argc, char **argv)
{
FILE *f=0;
char req[4096];
char junk[4096];
fgetline(req, sizeof req, stdin);
while(fgetline(junk, sizeof junk, stdin), strlen(junk) != 0);
if(strncmp(req, "GET ", 4) != 0) {
http_error(501);
}
for(int i = 4; i < sizeof(req); i++) {
if(req[i] == ' ') {
req[i] = '\0';
break;
}
}
for(int i = 4; i < sizeof(req) - 1; i++) {
if(req[i] == '.' && req[i+1] == '.') {
http_error(403);
}
}
f = fopen(req+5, "rb");
if(!f) {
if(errno == ENOENT || errno == EISDIR)
http_error(404);
else if(errno == EACCES)
http_error(403);
else
http_error(500);
}
printf("HTTP/1.0 200 OK\r\n"
"\r\n");
while(!feof(f) && !ferror(f)) {
size_t len = fread(junk, 1, sizeof(junk), f);
fwrite(junk, 1, len, stdout);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment