Skip to content

Instantly share code, notes, and snippets.

@opsJson
Last active March 20, 2022 21:38
Show Gist options
  • Save opsJson/3d7df74493da2380a898b25e13d8d6ee to your computer and use it in GitHub Desktop.
Save opsJson/3d7df74493da2380a898b25e13d8d6ee to your computer and use it in GitHub Desktop.
Easily create web apps on Windows.
#include <winsock2.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*///////////////////////////////////
easy-string
///////////////////////////////////*/
int indexOf(char* source, char* key, int pos) {
int i, j, dest;
assert(pos > -1);
for (i=0, j=0, dest=0; i<strlen(source); i++) {
(source[i] == key[j]) ? (j++) : (j=0);
if (j == strlen(key)) {
j = 0;
dest = i;
if (pos == 0) return dest - strlen(key) +1;
pos--;
}
}
return -1;
}
char* substring(char* source, int start, int end) {
char *dest, *back;
assert(start > -1);
assert(end > -1);
assert(start <= end);
dest = malloc(sizeof(char) * strlen(source) +1);
assert(dest != NULL);
strcpy(dest, source);
back = dest;
dest = dest + start;
*(dest + end - start + 1) = 0;
strcpy(back, dest);
return back;
}
void toLower(char *string) {
while (*string++) {
if (*string > 64 && *string < 91) {
*string = tolower(*string);
}
}
}
/*///////////////////////////////////
declaration
///////////////////////////////////*/
#ifndef ROUTES_MAX
#define ROUTES_MAX 50
#endif
typedef struct {
char *method;
char *page;
char *http_version;
char *headers;
char *body;
SOCKET connected_client;
char client_ip[20];
int client_port;
} Request;
struct ROUTES {
char *page;
void (*route_function)(Request *r);
} Route[ROUTES_MAX];
size_t route_count = 0;
void (*route_default_pointer)(Request*) = NULL;
void listenTo(char *ip, int port);
void route(char *page, void (*function)(Request *r));
void route_default(void (*function)(Request *r));
void sendTo(Request *r, char *body, char *headers, char *statusline);
void free_request(Request *r);
/*///////////////////////////////////
implementetion
///////////////////////////////////*/
void route_default(void (*function)(Request *r)) {
route_default_pointer = function;
}
void route(char *page, void (*function)(Request *r)) {
assert(route_count < ROUTES_MAX);
Route[route_count].route_function = function;
Route[route_count].page = page;
route_count++;
}
void sendTo(Request *r, char *body, char *headers, char *statusline) {
size_t content_length;
char *response;
if (statusline[0] == 0) {
statusline = "200 OK";
}
if (headers[0] == 0) {
headers = "Content-Type: text/html\n"
"Connection: close\n";
}
content_length = strlen(body);
response = (char*)malloc(
(sizeof(char) * strlen(statusline))
+ (sizeof(char) * strlen(headers))
+ (sizeof(char) * strlen(body))
+ (sizeof(int)) //content-length
+ 50);
assert(response != NULL);
sprintf(response, "HTTP/1.1 %s\n"
"Content-Length: %i\n"
"Connection: close\n"
"%s\n"
"%s", statusline, content_length, headers, body);
if (send(r->connected_client, response, strlen(response), 0) == SOCKET_ERROR ) {
fprintf(stderr, "Couldn't send data with error %i\n", WSAGetLastError());
}
free(response);
}
void free_request(Request *r) {
free(r->body);
free(r->headers);
free(r->http_version);
free(r->page);
free(r->method);
}
void listenTo(char *ip, int port) {
WSADATA wsa;
SOCKET server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
int s, bytes_recieved;
char request[4096] = {0};
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
fprintf(stderr, "Couldn't start winsock with error %i\n", WSAGetLastError());
return;
}
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
fprintf(stderr, "Couldn't create a socket with error %i\n", WSAGetLastError());
return;
}
toLower(ip);
if (strcmp(ip, "localhost") == 0)
server_addr.sin_addr.s_addr = INADDR_ANY;
else
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
fprintf(stderr, "Couldn't bind ip to socket with error %i\n", WSAGetLastError());
return;
}
if (listen(server_socket, SOMAXCONN) == SOCKET_ERROR) {
fprintf(stderr, "Couldn't made the socket listen with error %i\n", WSAGetLastError());
return;
}
s = sizeof(client_addr);
while ((client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &s)) != INVALID_SOCKET) {
memset(request, 0, sizeof(request));
bytes_recieved = recv(client_socket, request, sizeof(request)-1, 0);
if (bytes_recieved == SOCKET_ERROR) {
fprintf(stderr, "Couldn't completely received request with error %i\n", WSAGetLastError());
closesocket(client_socket);
continue;
}
if (bytes_recieved == 0) {
fprintf(stderr, "Connection successfully closed\n");
continue;
}
Request r;
//getting method
if (indexOf(request, " ", 0) != -1) {
r.method = substring(request, 0, indexOf(request, " ", 0)-1);
}
//getting resource
if (indexOf(request, " ", 1) != -1) {
r.page = substring(request, indexOf(request, " ", 0)+1,
indexOf(request, " ", 1)-1);
}
//getting http version
if (indexOf(request, "\n", 0) != -1) {
r.http_version = substring(request, indexOf(request, " ", 1)+1,
indexOf(request, "\n", 0)-1);
}
//getting headers
if (indexOf(request, "\n\r", 0) != -1) {
r.headers = substring(request, indexOf(request, "\n", 0)+1,
indexOf(request, "\n\r", 0)-2);
}
//getting body
r.body = substring(request, indexOf(request, "\n\r", 0)+2,
strlen(request)-1);
//setting client info
r.connected_client = client_socket;
r.client_port = htons(client_addr.sin_port);
strncpy(r.client_ip, inet_ntoa(client_addr.sin_addr), 19);
int i;
for (i=0; i<route_count; i++)
if (strcmp(Route[i].page, r.page) == 0) {
Route[i].route_function(&r);
break;
}
if (i >= route_count && route_default_pointer != NULL) route_default_pointer(&r);
free_request(&r);
closesocket(client_socket);
}
WSACleanup();
}
/*///////////////////////////////////
testing
///////////////////////////////////*/
void index_page(Request *r) {
printf("Connected to %s:%i\n", r->client_ip, r->client_port);
printf("%s %s %s\n%s\n%s\n\n", r->method, r->page, r->http_version,
r->headers, r->body);
sendTo(r, "Hello, World!", "", "");
}
void foo(Request *r) {
sendTo(r, "<!DOCTYPE html><html><head><title>"
"404 Not Found</title></head><body>"
"<h1>Not Found</h1>The requested URL was not found"
" on this server.</body></html>", "", "404 NOT FOUND");
}
int main() {
route_default(foo);
route("/", index_page);
listenTo("localhost", 80);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment