Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
36

Before you buy a domain name, first check to see if it’s haunted

from Bryan Braun - Blog [alt+shift+b] in technology

In mid-2022 I bought a new domain name. The name was musicbox.fun. I got it for a side-project, an interactive online music box that I had built and hosted at musicboxfun.com. The new name was shorter and more quirky. I felt lucky to have grabbed it. Unfortunately, musicbox.fun had a history. Before I bought it, the domain was used to host pirated music. musicbox.fun, as it existed in 2018 (before I owned it) From June 2018 to February 2021, the site racked up thousands of copyright violation complaints. Over 20,000 of its urls were delisted by Google (and other search engines) before the site went offline in 2022. I had no idea, of course. It wasn’t until I had redirected all of my musicboxfun.com traffic to musicbox.fun that I noticed that something wasn’t right: my web traffic from organic search dropped to zero. I assumed it was temporary so I double-checked my process and waited for awhile, but it never really recovered. It wasn’t until a year later that I discovered the copyright violations and learned that the domain name was compromised. Apparently, this is a thing that happens to domain names, but as far as I know, there’s not really a name for it. When I described it to my wife, she said “Oh, so it’s haunted.” “Haunted” is the perfect word for this: Something terrible happened at the domain name in the past. On the surface, nothing seems wrong with the domain name. Then there are signs that something isn’t right. Obligatory jump-scare when you discover what happened. Internal debate: do you abandon it or try to fix it? There’s a ton of superstition around how to fix it. Superficial fixes don’t seem to work. When there's something strange with your domain name, who you gonna call? So to summarize, I’m saying a domain name is “haunted” when something in its past gives it a poor reputation among search engines, affecting its ability to rank in search results, even after it changes ownership. The inner-workings of search engines are notoriously opaque*,...
25th Oct 2024

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from Bryan Braun - Blog

Klara and the gift of curiosity

In October, a new movie will be released based on one of my favorite books, Klara and the Sun. This has happened a lot for me recently (see The Three Body Problem, The Martian, Project Hail Mary, and Tomorrow and Tomorrow and Tomorrow). I know it’s cliché to say that the book is better, but that has generally been my experience. The Martian was groundbreaking but when you force it into a 2-hour format for general consumption it becomes a forgettable action movie. The Klara trailer doesn’t give me much hope. The cheery, jokey vibe, feels nothing like the experience I had reading the book, so I wanted to take this opportunity to share what made it special to me. Note: I wrote a succinct, spoiler-free review back in 2024, so if you want the basics, I invite you to read that. For everybody else, let’s continue. Klara is an advanced humanoid robot—an Artificial Friend (“AF”)—who was designed to be a companion for children. We follow along as Klara is purchased from her store, meets Josie, her child, and assists Josie’s family as they navigate the challenges of their world. The story is told from Klara’s perspective, allowing the reader to see what she sees and feels. As a new robot, Klara is somewhat like a child, trying to piece together an understanding of the world, and the reader is brought along on that journey. We know from the beginning that Josie’s life is complicated and that there’s something unhealthy about her or her family, but neither we nor Klara understand what or why. The process of discovering what’s actually happening made the book very interesting. As an AI, Klara sees things differently than humans see things. She often focuses on things that a human would dismiss and breezes over things a human would care about. She also sees the world with fresh eyes, which allows her to make observations I wouldn’t have considered. For example, she notices that humans go to great lengths to avoid loneliness. This fear of loneliness, she observes, is at the root of nearly all human decisions (a surprising insight that I would never have considered). At the same time, Klara is naive. At times, I found myself wondering if I could trust her observations and conclusions. One of the themes that emerges throughout the story is the question of whether humans are replaceable. The robots in the story are different from humans, but they’re clearly intelligent and capable of doing human work. Klara often expresses simple emotions like joy and fear, which help her care for Josie. The humans caring for Josie, have greater emotional range, but it’s almost a liability. The mother’s grief over her other daughter’s death has left emotional scars, and her neighbor’s guilt has left her incapacitated in many ways. The humans are trying to hold it together, but they’re clearly volatile while Klara is endlessly patient, optimistic, and kind. I was originally turned off by Klara’s obsession with the sun. She gets this idea in her mind that somehow the sun could help heal Josie from her sickness, and it was obvious to me that Klara was confused. I knew that the sun was a distant ball of gas, but to Klara, a solar-powered robot, it was a magical source of life and rejuvenation. I became certain that her programming as a robot (and her early formative experiences in the store), were throwing off her judgement. Clearly, she was blinded by what she was, and thus wasn’t able to see that her side-quests would have no effect and waste precious time. But I was wrong. The sun healed Josie, not because it was an anthropomorphic life-giver that took pity on Josie, or respected Klara’s sacrifice. It healed Josie because it gave everyone hope. It gave them hope at their lowest moments, when they were willing to throw away logic, and try anything if it might help her get better. To Klara, the sun was God. It was her distant life giver and the provider of miracles. That’s why Klara didn’t want to tell the humans all the details of her plan. She knew there needed to be space for all of them to have faith. This storyline about the sun impacted me because it was basically a speedrun of the religious-skepticism journey we often experience in the real world. We care so much about our worldview being evidence-based that we fail to realize that there are some things that evidence cannot give us. Things like hope, meaning, purpose, and a reason to act selflessly. The sun also brings back the fundamental question. If a robot can heal a child by exercising faith in God and risking her life to save the ones she loves, then how can there be anything left that’s special about humans? Are the humans not doomed to obsolesce? Online reviews for Klara and the Sun call it a “dystopian novel,” but I found the story quite hopeful. Human gene-editing, advanced artificial intelligence, and the obsolescence of humans are difficult topics to grapple with, but that world is coming fast. Some parts are already here. This story paints a picture of people finding a way to navigate it. Some people embrace the future (often paying heavy costs), some run from it, some fight it, and others accept it. But they all find a way. You and I get to decide how we respond to our own changing world, but if I can take one lesson from Klara it would be to keep an open mind. We become so certain of what we know that we forget to leave space for what we don’t. Curiosity is a gift. If we allow it to fade as we mature, we lose the opportunity to see things that could change our lives for the better. Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.

4 weeks ago 2 votes
You are not your grand plans

“You are not your grand plans. You are your daily patterns.” I love this quote from James Clear because it hurts me in all the right ways. At my worst, I feel like my daily patterns are at war with my grand plans. When I’m fighting a daily battle and willpower is slipping, I need every reminder that this moment, right now, is critical. Because it is! Your body is the result of your daily food and exercise choices, not your healthy ambitions. Your mind is the result of your regular media choices, education environment, and adjacent relationships, not an independent observer, hovering uninfluenced above your day-to-day interactions. Your character is the result of your actual sacrifices—for others, for your integrity, and for the common good—not your generous aspirations. When I’m struggling with daily patterns, it’s helpful for me to look at the times I was rocking it. I’ve had periods of my life when my workouts were really consistant, or I journaled every day, or I always woke up early. What contributed to those things? Often, it was social pressure, an accountability buddy, or a change of environment that pushed me into a productive place (underrated benefit of having a blog: it’s a historical record of your successes and failures). Of all the things I might learn looking back at these experiences, perhaps the most important is that it’s never been easy. I’ve got 15+ years of posts documenting the battle. Sometimes I’m winning and sometimes I’m losing, but I’m always fighting, and that’s a daily pattern too. Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.

11th Jul 2026 2 votes
Quality vs quantity in the age of AI

Over the last four months I’ve increased my use of AI for web dev work pretty dramatically. I use it every day at work, as do most of my coworkers. I don’t think it’s disputed anymore that AI-assisted development can save a lot of time and effort. The question is, what do we do with all that surplus? The standard narrative in the industry is to use it to go faster. Ship three features a day instead of one. Get a half-dozen agents working in parallel. 10x your productivity. If you don’t move fast, your competitors will! I get it. Speed is good and it has benefits beyond just finishing more stuff per unit time. Speed matters! But we live in an era of extreme consumer choice, especially in the world of software. Even pre-AI, there were dozens of good email clients, to-do lists, fitness apps, and analytics tools, all chock-full of useful features at reasonable prices. What is “going faster” going to give us? Even more options, with even more features? Apparently yes. In the past quarter, iOS app store submissions have risen by 84 percent, and Hackernews, “ShowHN” submissions have nearly tripled. We live in an era of software abundance. But as software grows increasingly abundant, attention grows increasingly scarce. Attention was scarce even before AI but it’s going to get worse. Consumers have more choices than ever, and increasingly those choices are becoming undifferentiated as the industry uses AI to produce them. What if we did the opposite? Instead of using your AI surplus to go faster, what if you used it to go deeper? What if, instead of building ten good features, you built two amazing ones? What if, instead of blasting out a dozen landing pages, you poured your attention and care into a home page that knocked someones socks off—one that could not have been built by an AI, because nothing like it could have been found in the training data? What if you doubled-down on performance? On accessibility? On user-experience? On creating a strong personal touch? It would stand out! That matters, arguably, even more than speed. Striking a balance The more I thought about this, the more I recognized it as the same ol’ quality vs quantity debate, where it pays to strike a balance: If we pour all our surplus time into quality, we end up hurting quality by failing to iterate. If we pour all our surplus time into quantity, we end up hurting speed as tech debt accumulates1. But what’s the ideal balance? Is it 90% quality, 10% speed? 50% - 50%? How would you spend your AI surplus? Remember: Slow is smooth, and smooth is fast. ↩ Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.

27th Apr 2026 1 votes
Links #14

See below for links to recent things that have made me think. It’s quite the mix of mediums (animated videos, short posts, letters, and 6-hour podcasts), but it wasn’t until I gathered them that I noticed a recurring theme: sacrifice Sometimes the world imposes constraints on us, forcing us to choose what matters most. What do we do when those moments come? Some of my favorite stories (both ancient and modern) explore these moments, and you’ll find elements of that in the list below. What’s Really Going on in El Segundo A 14-minute video about the hardware startup scene in El Segundo California, by Jason Carman. Some of it is hype, of course, but I’m impressed by the vision and culture of optimism they are offering to a world where so many young people are flailing and drowning in zero-sum status games. When a young man or woman comes up to me and says, “I’m not sure exactly what I want to do with my life,” “I’m having a really hard time orienting myself,” “I’m not sure what the point is, but I want to build something great and meaningful,”—that is one of the best consequences of everything that we’ve done. Making more water is a big deal, energy abundance is a big deal, …all of this is great. But just being able to give people some vision for the future—that is one of the most important things. We have to sacrificially build hard, real, material, things to create a future worth living in. I’ve been watching a bunch of Jason’s videos, and they’re all great medicine for the negativity that afflicts most news media. Offline 23 hours a day Derek Sivers describes his new home in the woods, an alternate world without AI, connectivity, or mental shortcuts. I know people have been been retreating like this for centuries, but the craziness of the world, and the busy-ness of my current life make such a retreat feel like a luxury. All it takes is for one to work out A short post about those moments when the rejections keep coming. These processes – college admissions, job searches, home buying, finding a partner – can be emotionally brutal. … All it takes is for one to work out. And that one is all you need. During my job search last year, I had a really exciting opportunity fall through at the end. It felt like a crushing blow. It would have been so perfect, I lamented. But looking back now, I don’t even care. Another one worked out (a better one, even). Knowing that rejections don’t actually matter is great medicine and a legitimate source of hope for anyone still fighting. Dan Wang’s 2025 Letter Dan Wang, author of a bestselling book about China and America, uses his end of year letter to compare the two countries and offer some thoughts. His writing struck a chord for me. It was informed and clever, full of interesting takes that demonstrate his deep understanding of the two nations. I added his book (Breakneck) to my list. Forevergreen A cute animated short story with a powerful message about sacrifice. I watched it twice—once with my wife, and again with my kids. Both times it sparked some great discussions. I think everyone should watch it. Child’s Play Sam Kriss profiles the newest, most eccentric, batch of Gen-Z founders. The way he presents their companies make them look exactly like what the fevered minds of a generation raised on social media algorithms would produce. Extreme, attention-grabbing, and impossible not to look away. Stacks of Labubus. Sperm racing. Reading this felt like I was being transported into another dimension—one where the most absurd, amoral corners of online culture have escaped into the physical world. Is it real or fake? For the luls? Can anyone even know? Along the way, he was also able to work in this fantastic quote: If we ever get AI that is strong enough to basically be God and solve all of our problems, it will need to use the same techniques that the actual God uses in terms of maintaining some distance. I do think it’s possible that the AI will be like, “Now I am God. I’ve concluded that the actual God made exactly the right decision on how much evil to permit in the universe. Therefore I refuse to change anything.” Lex Friedman interviews DHH At over 6 hours, this is the longest podcast interview I’ve ever listened to, and I doubt I would have finished it if DHH wasn’t so sharp and entertaining. DHH is known for his strong opinions and I was impressed at his ability to articulate his thinking with clarity and appropriate nuance throughout the interview. The part where he explains the beauty of the Ruby language (from both a practical and philosophical perspective) made me want to write more Ruby, and many of the other topics got me thinking as well. Costless Sacrifice When AIs can print job applications for pennies, fill up the internet with thinkpieces, and commit industrial-scale quantities of code, is there anything left for us humans to create? Packy McCormick says: yes. What still matters, is what has always mattered, and that is sacrifice. People still want a connection to the stories they read and the music they listen to. Employers still wants to hire someone who cares. Recruiters never needed good cover letters for their own sake… they needed someone who cared enough to sacrifice the time and effort to write them well. They still need those people, even if cover letters are no longer a good way to find them. My takeaway: even in a world flooded with AI-generated content, there will still be a place for those of us who care enough to sacrifice for our work. Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.

30th Mar 2026 1 votes
250 lbs

Six months ago, while I was setting up a new code editor, I noticed that the default font size felt just a bit too small, when displayed on my monitor. Not a big deal, I just bumped it up one size and went back to my work. Then it happened again, this time, when reading sheet music on my phone. “That’s weird,” I thought, as I increased the size. “This didn’t bother me before.” I had always had perfect, 20-20 eyesight. When I finally realized that I was losing some of that sharpness, I felt a loss. It wasn’t the first time, though. About two years ago, I started having wrist pain while typing. On one particularly bad day, I became very worried. “Typing is how I provide for my family. What will I do, if I can’t type?” Soon I discovered that wearing wrist braces at night helped make the pain go away. I remember laying in my bed in wrist braces, thinking, “I’m 36 years old. I’m too young to need wrist braces for the rest of my life,” and I felt a loss.1 After a few losses like these, it would be easy to adopt a narrative that I’m in physical decline, losing capability daily, with all my best achievements in my past. It’s a sad story. A fragile story. I decided that one way I could push back against this story is to set a new weightlifting goal: a 250-pound bench press. It was an unthinkable goal back when I benched 200. I didn’t plan on going heavier, but I enjoyed my weightlifting routine, so I kept showing up. By the time I hit 235, I realized that maybe 250 was possible. I felt excited and motivated just thinking about it. I wanted to go for it. But just like last time, I hit a plateau.2 I was able to bench 245 once, last summer, but I spent the next 6 months unable to do it again. As I turned 39, I wondered if I was fighting against time. And then it happened. All of us are going to have to learn how to grow old. The aging itself is easy, but learning how to handle the losses is more challenging. Today, I can tell myself, “my eyesight may be declining, but I’m stronger than I’ve ever been.” Next year, who knows. Maybe I’ll get into pickleball. There are endless opportunities for personal growth, and if we exhaust the supply of physical milestones we can still progress intellectually, creatively, and spiritually. Life offers plenty of PRs to pursue, if we’re willing to look for them. Fortunately, I didn't end up needing to wear wrist braces for the rest of my life. After some trial and error, I learned that my pain was ultimately caused by poor ergonomics from using my laptop keyboard and trackpad for extended periods. Once I got set up with an ergonomic keyboard and mouse, the pain went away. It's still a bit of a loss (I can't just roll into a weekend hackathon with only a laptop anymore) but I'm glad I can still do the work I enjoy. ↩ In my last weightlifting post, I talked a bit about breaking through plateaus. This time, the key intervention was simply eating more calories (something I've avoided in the past in an effort to moderate body fat). Eating more calories increased my body fat a bit, but also helped me build muscle. Professional weightlifters eat a lot and exercise a lot. It's not an efficient use of time but it's fun (especially if you like eating and exercising). ↩ Thanks for reading this post via RSS! Let me know your thoughts by leaving a comment on the original post or sending me an email.

16th Feb 2026 1 votes

More in technology

Is This A Joke? In The Auth Header? (F5 BIG-IP UnAuth Heap-Overflow to RCE CVE-2026-94127)

Well, well, well, well, well, well, well, well, well, well, well, well, well, well, well. We're back. Sorry. We've been watching the onslaught of vulnerabilities flood the internet. Every man, dog, and their grandmas (apparently?) are now using LLMs to find and reproduce vulnerabilities - it’

15 hours ago 1 votes
The Reason You Prohibit Things

You want less of them. That’s the reason. You may find that it’s too hard to stop people from doing the thing, literally blood, sweat, and tears trying to prosecute people, but that’s a different thing.

17 hours ago
Solitaire Alone Together

Solitaire Alone Together I made a new game. It's called Solitaire Alone Together. It's Windows 98 solitaire, but you can play with everyone else on the internet. Read the full post on my blog! Here's a raw link, if you need it: https://eieio.games/blog/solitaire-alone-together

3 days ago 1 votes
All The Ways I Broke My Website

This post is a living diary of all the times I messed up something with my website in a funny way. I value those who have the confidence to own their mistakes and share the learning with others, and so this is me doing just that! That Time I Accidentally Made a Tarpit That Time I Accidentally Made Really Large Headers That Time I Accidentally Made a Tarpit Back to Top A "tarpit" is an unofficial term used in computing to describe an intentionally slow response to a request. In these modern times many people are using tarpits as a way to combat the relentless theft of data by AI companies, although there's little to no evidence of that actually being in any way effective. I don't use tarpits, at least not intentionally, but there was that one time when I accidentally created a tarpit and trapped all visitors in it. As I've shared previously, I refuse connections from IP addresses that are blocked or belong to a blocked subnet, and I enforce this firewall during the TCP handshake. The logic here is straightforward: there's no reason to waste resources doing a TLS handshake, accepting an HTTP request, and then rejecting the connection if I already know I'm going to reject it at the earliest step. At the time, the code worked like this: the HTTP server would repeatedly call the Accept() function below expecting a new connection. I've added some comments to help explain the logic. func (l *firewallListener) Accept() (net.Conn, error) { // Accept the connection from the TCP listener. This blocks until there is a connection to accept or the listner was closed. conn, err := l.l.AcceptTCP() if err != nil { return conn, err } // Separate the IP address out from the remote address (which includes the port) ip := utils.SocketStringToIPAddress(conn.RemoteAddr().String()) if ip == nil { return nil, nil } // Check if it's blocked, if so close the connection and return a refuseError if IsBlocked(ip, true) { conn.Close() return nil, &refuseError{} } // Otherwise return the connection on to the HTTP server return conn, nil } If the incoming connection was from a blocked IP then I'd return a refuseError. I need to use a specific error interface because the HTTP server will halt if it encounters a non-temporary error from the call to Accept(), so I need to return an error that satisfies the definition of a temporary error. I defined refuseError like this: type refuseError struct{} func (e *refuseError) Error() string { return "." } func (e *refuseError) Timeout() bool { return true } func (e *refuseError) Temporary() bool { return true } func (e *refuseError) Is(err error) bool { return err == context.DeadlineExceeded } This did accomplish the goal of rejecting connections before the TLS handshake for blocked addresses, but it had one really unintended and difficult to track down side-effect. Accepting connections is done serially, after which servers typically then process that request on a dedicated thread (or in Go's case a goroutine). This means that any delays during the accept loop will block all incoming connection. What I had missed while reviewing the code for Go's HTTP server is that when it receives a temporary error from Accept() is that while it doesn't abort, it does sleep for up to a maximum of 1 second. This sleep blocks the entire server for all incoming connections. You can see a trimmed copy of the code that does this below, with some marks I've added which I will explain. // src/net/http/server.go // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. for { // (1) rw, err := l.Accept() if err != nil { if s.shuttingDown() { return ErrServerClosed } // (2) if ne, ok := err.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } s.logf("http: Accept error: %v; retrying in %v", err, tempDelay) // (3) time.Sleep(tempDelay) continue } return err } connCtx := ctx if cc := s.ConnContext; cc != nil { connCtx = cc(connCtx, rw) if connCtx == nil { panic("ConnContext returned nil") } } tempDelay = 0 c := s.newConn(rw) c.setState(c.rwc, StateNew, runHooks) // before Serve can return // (4) go c.serve(connCtx) } At mark 1 the server calls the Accept() function, this is the exact function that I defined above where I might return a temporary error. At mark 2 it checks if an error was returned, and if so if that error is temporary. If there was a temporary error, at mark 3 it sleeps for an increasing amount of time up-to 1 second, otherwise, at mark 4 it processes the connection on a dedicated goroutine, which allows the server to accept the next connection. I'm not entirely sure why the Go developers added this sleep delay and the change when it was introduced doesn't provide any meaningful insight. Regardless, it caused significant latency connecting to my website when a flood of rejected requests was coming in. It just goes to show how important it is to write meaningful commit messages, because you never know when somebody might come back years later wondering "why was this done?". I sure home I don't come to eat those words later. Coincidentally, you can actually see this happening if you look carefully at one of the metric graphs I shared in my first post about my server's security model: Securing My Web Infrastructure. This is the graph I shared in that blog post and while I didn't know it at the time, the fact that these request spikes all cap-out at around 60 requests per minute was not a coincidence. These requests were not being made with a limit in mind, attackers rarely ever care about things like that, instead it the accidental tarpit I had created. The downside to this was that while the malicious requests were being rate-limited, all requests were being rate-limited, up to a point of taking so long they timed out. The Fix Fixing the issue was relatively straightforward enough. Instead of returning a temporary error to the HTTP server during the accept loop, just don't return anything at all and wait for the next valid connection. func (l *firewallListener) Accept() (net.Conn, error) { for { conn, err := l.l.AcceptTCP() if err != nil { return conn, err } ip := utils.SocketStringToIPAddress(conn.RemoteAddr().String()) if ip == nil { return nil, nil } if IsBlocked(ip, true) { conn.SetLinger(0) conn.Close() continue } return conn, nil } } Now, when the HTTP server calls Accept(), the only time it returns is with a connection from an IP that isn't blocked, or if there genuinely is an error. No more sleep delays, no more excessive timeouts. That Time I Accidentally Made Really Large Headers Back to Top For about 10 years now all major browsers have support for a security feature known as a Content Security Policy or CSP. A CSP is an HTTP header provided by the server that instructs the browser on where it can load assets from, this could be scripts, images, stylesheets, fonts, etc. The objective of using a CSP is to prevent against injected HTML that tries to load assets, such as a malicious Javascript file, from a remote source. With so much user-provided content being available online, it's very possible for this to happen without an attacker compromising the entire web server. CSP protects against that by saying "scripts can only be loaded from these domains". That's a really simplified way of looking at it, anyways. My web server supports injecting the CSP header automatically, but before I go on I need to explain a little bit about the structure of my web server. When an incoming HTTP request is accepted (having passed all firewall checks and assertions), we look at the destination host for the request. This can either be the value of the Host header or as specified during the TLS handshake. We then look at a map of hosts to apps. Apps are just an interface that accept a few methods: type App interface { Cleanup() ReloadConfig() ServeHTTP(rw http.ResponseWriter, r *http.Request) Setup(dataDir string) error Shutdown() } One of the apps is the Proxy app, which is a reverse proxy - it accepts the incoming HTTP request and then proxies it on to another host. This is a very common design, especially with increasingly complex TLS setups. Because each app is unique to a host, and different hosts have different requirements for CSP rules, the proxy app includes a CSP preset that we use to build the header value, or skip it entirely. When the proxy app was going to copy an HTTP request to the downstream host, it would build the CSP header, however there was a slight bug... func (a *App) ServeHTTP(rw http.ResponseWriter, inRequest *ht2.Request) { // --snip -- if a.CSP != nil { a.CSP.ConnectSrc += " " + inRequest.Origin } CopyHttpRequest(inRequest, outRequest, rw, CopyHttpRequestOptions{ Origin: inRequest.Origin, Csp: a.CSP, Cors: a.CORS, AddHeaders: !a.SkipHeaders, UseHTTP3: a.UseHTTP3, InsecureTLS: a.InsecureTLS, }) } I'm really unsure as to what I was doing with the line to append to the ConnectSrc, but the impact is that I'm appending to a variable that lives on the App, rather than a variable that is per-request. This meant that every time there was a request to the app, any request at all, the origin would be appended to the header value. This went on for quite a long time unnoticed and unresolved, largely because I am constantly tweaking and tinkering with my web server, after all, it's how I made having a website fun again. Each time I restarted the server process, the header value would be reset, but only for it to continue to grow and grow. Eventually, after a period of being busy with other matters, the server process stayed running for long enough that the header value grew too large and HTTP clients began to reject it. There is no defined maximum for an HTTP header value, however most HTTP clients use 100KiB, which is perfectly reasonable, and this header value would continue to grow well beyond that. Diagnosing this issue turned out to be difficult as tools like Curl would fail with errors relating to entities being too large, but stopped short of saying what specifically. I eventually used openssl s_client to send an HTTP request by hand and observed my terminal window being filled with a domain name repeated thousands of times. Looking at the commit history, it was really unclear why I added the culprit lines of code. The commit message just says "Improved CSP support". It just goes to show how important it is to write - hey look it's those words I'm now having to eat! The Fix The fix was to just delete those three lines of code. Yup, it really was that simple, and fixing this bug actually made a larger positive impact than I had expected, as it was immediately clear when I fixed the bug by looking at outbound network bytes: So much traffic was being wasted on excessive header sizes. You might look at these mistakes I've made and think "wow, Ian, these are some obvious mistakes, I never would have made them!" to which I say "good for you!" with the utmost sarcasm and disdain. I enjoy making and refining software, and making anything means making mistakes along the way. Each time I make mistakes such as the ones above, I improve my skills of investigation, diagnosing, and repair. Skills that, judging by my peers in the industry, seemingly everyone is quickly willing to throw away because a robot does it "better" than you. Header Image: "Car accident on the Ffestiniog to Bala road. Nobody was hurt" by Geoff Charles, CC BY-SA 4.0, via Wikimedia Commons.

5 days ago
Buienwatch, a custom Home Assistant integration for Buienradar and Buienalarm graphs on your Apple Watch

Back in 2021, I wired up data from Buienalarm and Buienradar through Node-RED and a big pile of Jinja2 templates to get a rain forecast graph on my Apple Watch: eight Unicode block characters showing the next two hours in 15-minute chunks, glanceable without unlocking the phone. It worked, and I used it every day […] The post Buienwatch, a custom Home Assistant integration for Buienradar and Buienalarm graphs on your Apple Watch appeared first on Style over Substance.

a week ago 0 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in