Skip to content

Instantly share code, notes, and snippets.

@ryankearney
Created February 5, 2010 23:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ryankearney/296370 to your computer and use it in GitHub Desktop.
Save ryankearney/296370 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <time.h>
#include <netinet/in.h>
typedef struct {
int ID;
char * title;
char * link;
char * date;
int upVotes;
int downVotes;
void * next;
} Article;
Article * root;
char * getVal(char * query, char * key) {
char * str = malloc(1);
int match = 0;
int pMatch = 0;
char * cur = query;
while (*cur != '\0') {
if (pMatch >= 1 && (*cur == '&' || *cur == '\n' || *cur == ' ')) {
break;
} else if (pMatch >= 1) {
str = realloc(str, pMatch+1);
*(str+pMatch-1) = *cur; ++pMatch;
} else if (match == strlen(key)) {
pMatch = 1;
} else if (*cur == key[match]) {
++match;
} else {
match = 0;
}
cur++;
}
if (pMatch >= 1) {
str[pMatch-1] = '\0';
return str;
}
free(str);
return NULL;
}
char from_hex(char ch) {
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}
char to_hex(char code) {
static char hex[] = "0123456789abcdef";
return hex[code & 15];
}
char *url_decode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
*pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
pstr += 2;
}
} else if (*pstr == '+') {
*pbuf++ = ' ';
} else {
*pbuf++ = *pstr;
}
pstr++;
}
*pbuf = '\0';
return buf;
}
void send_headers(FILE *f, int status, char *title, char *extra, char *mime, int length) {
char timebuf[128];
fprintf(f, "%s %d %s\r\n", "HTTP/1.0", status, title);
fprintf(f, "Server: %s\r\n", "redditserver/1.0");
if (extra) fprintf(f, "%s\r\n", extra);
if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
fprintf(f, "Connection: close\r\n");
fprintf(f, "\r\n");
}
void reddit(FILE *f) {
fprintf(f, "<HTML><HEAD><TITLE>Reddit Clone</TITLE></HEAD>\r\n");
fprintf(f, "\
<BODY><H1>Submit</H1><form action=\"/\" method=\"get\">Title:<input type=\"text\" \
name=\"title\" /> Link:<input type=\"text\" name=\"link\" /><input type=\"submit\" \
value=\"Submit\" /></form>\r\n");
if (root) {
fprintf(f, "<h1>Articles</h1>");
Article * cur = root;
while (cur != NULL) {
fprintf(f, "\
<p><font size=\"5\">%d<b><a href=\"/?up=%d\">&uarr</b></font><a href=\"%s\">%s</a>\
<br /><font size=\"5\">&nbsp;&nbsp;<b><a href=\"/?down=%d\">&darr</a></b>\
</font>%s -- %s</p>", cur->upVotes - cur->downVotes, cur->ID, cur->link, cur->title,
cur->ID, cur->link, cur->date);
cur = cur->next;
}
}
fprintf(f, "</BODY></HTML>\r\n");
}
int fsize(FILE * f) {
fseek(f, 0, SEEK_END);
int size = ftell(f);
fseek(f, 0, SEEK_SET);
return size;
}
int main(int argc, char *argv[]) {
int sock;
int port = 1337;
struct sockaddr_in sin;
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
while (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
printf("Failed bind\n"); sleep(2);
}
listen(sock, 5);
printf("HTTP server listening on port %d\n", port);
root = NULL;
while (1) {
int s;
int size;
int hsize;
char * buff;
FILE * t;
FILE * ht;
FILE * f;
s = accept(sock, NULL, NULL);
if (s < 0) break;
char * header = calloc(255, 1);
size = read(s, header, 255);
char * titleEnc = getVal(header, "title");
char * linkEnc = getVal(header, "link");
if (titleEnc && linkEnc) {
char * title = url_decode(titleEnc);
char * link = url_decode(linkEnc);
free(linkEnc);
free(titleEnc);
printf("Title: %s -- Link: %s\n", title, link);
char * s = malloc(30);
size_t i;
struct tm tim;
time_t now;
now = time(NULL);
tim = *(localtime(&now));
i = strftime(s,30,"%b %d, %Y; %H:%M:%S\n",&tim);
Article * new = malloc(sizeof(Article));
new->title = title;
new->link = link;
new->next = NULL;
new->date = s;
new->upVotes = 0;
new->downVotes = 0;
if (!root) {
root = new;
new->ID = 0;
} else {
int dupe = 0;
Article * cur = root;
Article * prev = NULL;
while (cur != NULL) {
if (strcmp(cur->title, new->title) == 0 || strcmp(cur->link, new->link) == 0) {
dupe = 1;
}
prev = cur;
cur = cur->next;
}
if (dupe == 0) {
new->ID = prev->ID + 1;
prev->next = new;
} else free(new);
}
}
char * upID = getVal(header, "up");
if (upID) {
int ID = atoi(upID);
Article * cur = root;
while (cur != NULL) {
if (cur->ID == ID) {
cur->upVotes++; break;
}
cur = cur->next;
}
}
char * dID = getVal(header, "down");
if (dID) {
int ID = atoi(dID);
Article * cur = root;
while (cur != NULL) {
if (cur->ID == ID) {
cur->downVotes++;
break;
}
cur = cur->next;
}
}
t = tmpfile();
ht = tmpfile();
reddit(t);
size = fsize(t);
send_headers(ht, 200, "Ok", NULL, "text/html", size);
hsize = fsize(ht);
buff = malloc(hsize);
fread(buff, 1, hsize, ht);
write(s,buff,hsize);
free(buff);
buff = malloc(size);
fread(buff, 1, size, t);
write(s,buff,size);
free(buff);
fclose(t);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment