this post was submitted on 22 Jan 2025
22 points (95.8% liked)

Programming

254 readers
7 users here now

Welcome to the Lemmygrad programming community! This is a space where programmers of all levels can discuss programming, ask for help with problems, and share their personal programming projects with others.


Rules

  1. Respect all users, regardless of their level of knowledge in programming. We're here to learn and help each other improve.
  2. Keep posts relevant to programming and related topics.
  3. Respect people's personal preferences. If you disagree with someone's choice of programming language, method of formatting code, or anything else, don't attack the poster. Genuine criticism is fine, but personal attacks are not.
  4. In order to promote breaks from typing, all code snippets must be photos of code written on paper.
    Just kidding :), please use proper markdown code blocks.

founded 2 years ago
MODERATORS
top 3 comments
sorted by: hot top controversial new old
[–] [email protected] 4 points 3 weeks ago

I don't even want to think about how much time and electricity is getting wasted each day because of all these massively bloated websites and webapps. Modern computers are insanely fast, yet webapps sometimes take more than 10 seconds to start up on a good day.

Personally I like my WebApps in C89

/* app.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifdef __linux__
#include <linux/net.h> /* For SO_REUSEPORT */
#endif

#define LISTEN_PORT 9000

#define REQUEST_TYPE_UNKNOWN 0
#define REQUEST_TYPE_GET 1

static const char *html_main = (
    "<!DOCTYPE html>"
    "<html>"
    "<header>"
    "<title>My first Web App</title>"
    "</header>"
    "<body>"
    "<h1>Hello World</h1>"
    "</body>"
    "</html>"
);

static size_t html_main_length;

static void http_reply(int cl_sock_fd,
                       const uint16_t status,
                       const char *status_msg,
                       const char *mimetype,
                       const size_t content_length)
{
    char buffer[0x400];
    int length;
    
    length = sprintf(
        buffer,
        "HTTP/1.1 %u %s\r\n"
        "Content-Type: %s\r\n"
        "Content-Length: %lu\r\n"
        "\r\n",
        status,
        status_msg,
        mimetype,
        content_length
    );

    write(cl_sock_fd, buffer, length);
}

int main(void)
{
    int32_t sv_sock_fd, cl_sock_fd;
    struct sockaddr_in sv_addr, cl_addr;
    socklen_t cl_addr_size;
    uint32_t option;
    char *input_buffer;
    size_t input_length, input_buffer_length;
    uint8_t request_type;
    
    memset(&sv_addr, 0, sizeof(sv_addr));
    sv_addr.sin_family = AF_INET;
    sv_addr.sin_addr.s_addr = INADDR_ANY;
    sv_addr.sin_port = htons(LISTEN_PORT);
    sv_sock_fd = socket(sv_addr.sin_family, SOCK_STREAM, 0);
    
    if (sv_sock_fd == -1)
    {
        perror("Unable to create server socket");
        return EXIT_FAILURE;
    }
    
    /* Tell it to re-use the address and port... */
    option = 1;
    
    if (setsockopt(sv_sock_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)))
    {
        close(sv_sock_fd);
        perror("Unable to setsockopt on socket");
        return EXIT_FAILURE;
    }
    
    if (setsockopt(sv_sock_fd, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)))
    {
        close(sv_sock_fd);
        perror("Unable to setsockopt on socket");
        return EXIT_FAILURE;
    }
    
    if (bind(sv_sock_fd, (struct sockaddr *)&sv_addr, sizeof(sv_addr)))
    {
        close(sv_sock_fd);
        perror("Unable to bind socket to address");
        return EXIT_FAILURE;
    }

    if (listen(sv_sock_fd, 0))
    {
        close(sv_sock_fd);
        perror("Unable to listen on socket");
        return EXIT_FAILURE;
    }

    input_buffer_length = 0x400;
    input_buffer = malloc(input_buffer_length);

    if (!input_buffer)
    {
        close(sv_sock_fd);
        perror("input_buffer == NULL");
        return EXIT_FAILURE;
    }

    html_main_length = strlen(html_main);
    cl_addr_size = sizeof(cl_addr);
    printf("Waiting for new connections on port %u ...\n", LISTEN_PORT);
    
    while (1)
    {
        cl_sock_fd = accept(sv_sock_fd, (struct sockaddr *)&cl_addr, &cl_addr_size);

        if (cl_sock_fd == -1)
        {
            perror("Error when accept()ing");
            break;
        }
        
        request_type = REQUEST_TYPE_UNKNOWN;
        input_length = 0;
        /* Read from the client */
        while (read(cl_sock_fd, input_buffer + input_length, 1) > 0)
        {
            if (input_length >= input_buffer_length)
            {
                input_buffer_length += 0x400;
                input_buffer = realloc(input_buffer, input_buffer_length);

                if (!input_buffer)
                {
                    close(sv_sock_fd);
                    close(cl_sock_fd);
                    perror("Failed to realloc() input_buffer");
                    return EXIT_FAILURE;
                }
            }
            
            if (input_buffer[input_length] == ' ')
            {
                if (request_type == REQUEST_TYPE_GET)
                {
                    printf("GET request: %.*s\n", (int)input_length, input_buffer);
                    
                    if (strncmp(input_buffer, "/", input_length) == 0)
                    {
                        http_reply(cl_sock_fd, 200, "OK", "text/html; charset=UTF-8", html_main_length);
                        write(cl_sock_fd, html_main, html_main_length);
                        break;
                    }
                    
                    http_reply(cl_sock_fd, 404, "Not Found", "", 0);
                    break;
                }
                
                if (strncmp(input_buffer, "GET", input_length) == 0)
                {
                    request_type = REQUEST_TYPE_GET;
                    input_length = 0;
                    continue;
                }

                break;
            }
            
            ++input_length;
        }
        
        close(cl_sock_fd);
    }
    
    free(input_buffer);
    close(sv_sock_fd);
    return EXIT_SUCCESS;
}

To compile on a UNIX-like system: $ cc -o app app.c -std=c89 -Wall -Wextra

[–] [email protected] 3 points 4 weeks ago (1 children)

Interesting article and approach. While I absolutely agree it's too easy to bloat with unneeded complexity on the off chance you might want it... I'm suspect of how his app was built. These frameworks and tools wouldn't be widely used if they were shit.

But in general, good lesson in "less is more".

[–] [email protected] 11 points 4 weeks ago

Having worked with a lot of these tools and frameworks extensively I really do think they are shit for most use cases. I also find that software industry love doing cargo culting where people just use whatever tools big companies like Google or Meta put out without actually considering whether these tools are useful in their specific circumstance. The big companies also encourage this because they effectively get to outsource training on their internal tools to other companies, and then poach top talent that's already familiar with their stack. The way he structured the app is perfectly reasonable. Treating the UI simply as a presentation layer removes a ton of complexity from the architecture.