I managed to track down the last remaining crashes, and the primary one WAS in fact in one of my own functions. I'm using a new string system that I haven't tested much that I call "defstr" (double ended flat string), it's basically a continuous chunk of memory where you can add/remove data from either start or the end without causing re-allocations or big data moves, and it re-allocates if it needs more space (or shifts around if there's a lot of extra space in the opposite end). It's perfect for this since I can add new data to the end of the buffer, and remove data from the start when I read it. Anyway one of it's functions had a missing piece that eventually caused the reallocation to fail. The weird thing is how uncommon this problem was, I should have definitely run into it before, I even tested the functions when I made them but didn't encounter it.
The second crash was much rarer and I hadn't seen it in a long time, this one actually gave a windows crash prompt which tells me it's an access violation.
I found the cause of it when I started thinking of how I can start re-using old IO and Socket data again so it won't just create new ones infinitely. And as soon as I removed the line that closes sockets, the crash no longer occurs. I had to change the design of things a bit such that the socket info keeps track of how many IO operations are active on it, and is only closed when the last active IO operation is removed.
So now it works very consistently, it never hangs or crashes or gets stuck or fails to send resources no matter what I try on the browser's side, it never exceeds 6 active sockets and 13 active IO operations on a single browser loading a page with 30 images, and it reverts to around 17 MB memory usage after each page refresh. I actually load images directly into memory when I send them, but I think it's possible to pipe files straight into the IOCP. That'll be required eventually since I want to minimize memory usage headaches (though I'll probably use Nginx for static files anyway). There might also be some possible exploits, for example I'm not sure if sockets ever time out on their own, so a malicious user could fill the server with passive connections. There's an option to time out the IO event, but I'll just have to see.
But anyway I want to get to the actually interesting part now, which is making the application server. I can already parse the most important parts of the HTTP header to figure out whether it's a POST or GET request, and what page/file the user wants to access. I don't think there's actually anything very complicated about this, reading the headers is simple, sending files is simple, the hardest part might be to parse form data, especially file uploads (I'll also need a way to pipe the file data straight into a file rather than loading the whole thing into memory). I experimented with normal forms and multiplart forms, and the data seems pretty straightforward, though I didn't try file uploads yet.
Webm related, I can already serve pages and files. Besides minor tweaks here and there (and the linux equivalent of the server), there's only 1 big obstacle before I can start working on Nchan, and that's the database. I actually have no clue how to connect to a database from a C program like this. I know how to do text commands since I've used FFMPEG from one of my programs before, but you need to actually log in to the database and stuff so I don't think it's the same at all.
Anyway now I can finally stop blogposting about this.