Last active
March 20, 2022 21:38
-
-
Save opsJson/3d7df74493da2380a898b25e13d8d6ee to your computer and use it in GitHub Desktop.
Easily create web apps on Windows.
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
#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