Dilbert





The Daily WTF

Error'd: Professionals Wanted;

"Searching for 'Pink Tile Building Materials' in Amazon results in a few 'novelty' items sprinkled in, which, to me, isn't a huge surprise," Brian G. wrote, "But, upon closer inspection...professional installation you say?"

 

"Well, at least they're being honest," Josh wrote.

 

Brian writes, "You know, I wonder if 'date math' would qualify as business technology? If it doesn't, they should probably make an exception."

 

"Spotted in Belgium, I can only assume this is Belgian for 'Lorem Ipsum'," writes Robin G.

 

Wouter writes, "Cool! Mozilla has invented time travel just to delete this old Firefox screenshot."

 

"To cancel or...cancel...that is the question...really...that's the question," Peter wrote.

 

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


CodeSOD: True Confession: Without a Map;

Today, we have the special true confession from Bruce, who wrote some bad code, but at least knows it’s bad.

Bruce is a C# developer. Bruce is not a web developer. Someone around the office, though, had read an article about how TypeScript was closer to “real” languages, like C#, and asked Bruce to do some TypeScript work.

Now, in C# parlance, your key/value pair data-structure is called a Dictionary. So, when Bruce got stuck on how to store key/value pairs in TypeScript, he googled “typescript dictionary”, and got no useful results.

Disappointed, Bruce set out to remedy this absence:

export class KeyValuePair<TKey,TValue> {
    Key: TKey;
    Value: TValue;
    constructor (key: TKey, value: TValue) {
        this.Key = key;
        this.Value = value;
    }
}
export class Dictionary<TKey, TValue>{
    private Collection: Array<KeyValuePair<TKey, TValue>>
    private IndexMap: Map<TKey, number>
    private index: number;
    public tryAdd(key: TKey, value: TValue): boolean {
        if (this.containsKey(key)) {
            return false;
        } else {
            var kv = new KeyValuePair(key, value);
            this.IndexMap.set(kv.Key, this.Collection.push(kv) - 1);
            return true;
        }
    }
    public tryRemove(key: TKey): boolean {
        var i = this.indexOf(key);
        if (i == -1) {
            return false;
        } else {
            this.Collection.splice(i, 1);
            this.reMap(i, key);
            return true;
        }
    }
   public indexOf(key: TKey): number {
        if (this.containsKey(key)) {
            return this.IndexMap.get(key);
        } else {
            return -1;
        }
    }
    public containsKey(key: TKey): boolean {
        if (this.IndexMap.has(key)) {
            return true;
        } else {
            return false;
        }
    }
   private reMap(index: number, key: TKey) {
        this.index = index;
        this.IndexMap.delete(key);
        this.IndexMap.forEach((value: number, key: TKey) => {
            if (value > this.index) {
                this.IndexMap.set(key, value - 1);
            }
        });
    }

//the rest is recreating C# dictionary methods: getKeys(),getValues(), clear(), etc.
}

The dictionary implementation stores an array of key/value pairs. Now, it’d be expensive to have to search every item in the collection to find the appropriate key/value pair, so Bruce knew he needed to find a way to map keys to values. So he used a Map to store pairs of keys and indexes within the array.

He spent an entire afternoon coding this masterpiece before realizing that Maps stored key/value pairs… just like a dictionary.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!


A Problem in the Backend;

Gary works at a medium company. Big enough that workers are specialized in their duty, but small enough to know people in other departments and to make turf wars a little more close and personal: danger close. Most of the departments see themselves as part of a team, but a few individuals see themselves as McCarthy, who will themselves alone save the company and defeat the enemies (who are all spies inside the company sent to destroy it from the inside).

One of these individuals is named Eric. Eric is close to a Kevin. Eric is the front-end developer, and neither likes nor cares about what happens on the backend. Whenever Eric has an issue, he blames the backend. CSS rendering glitch? Backend problem. Browser crash? That’s the backend problem. Slow UI, even when all the data is cached clientside? Definitely a backend problem. Gary used to get mad, but now knows that Eric is so dumb that he doesn’t even know how dumb he is.

Eric grates on people’s nerves. Since nothing is his problem, he doesn’t seem to have any work, so he bugs backend developers like Gary with terrible jokes. A typically Eric joke:

“Do you know why they call back end developers back end,” Eric asked.
“No?” Gary questioned
“Because you look like your back end!”
“ …?…ha”

Another typically Eric joke is taping up backend developer work in progress on the men’s restroom stall. Gary knows it was Eric, because he came to ask the connection details for the color printer (the printer nearest Eric is grayscale only).

The first telling is almost funny. The second telling is less so. The 100th joke while Gary is trying to debug a large Perl regex, and Gary is less inclined to be sympathetic.

Eric and Gary have had in a couple danger close incidents. The first time involved an issue where Eric didn’t read the api naming conventions. He wrote front-end code with a different naming convention, and insisted that Gary change a variable name in the API. That variable is referenced twice on his front end and and in over 10,000 lines of backend code.

The most recent danger close incident involved the Big Boss. The Big Boss knows how Eric can be, so he generally gives Eric some time to find out the problem, but features need to ship. Eventually, the Big Boss calls a meeting.

“Hey Gary, Eric, I don’t know whose fault it is, but when I log in as a superuser, log out and log back in as a limited user, I still see data for a superuser. This is an information security issue. Now I’m not sure which part is causing this, but would you know?” asked Big Boss.

“I’m sure it’s the backend.,” Eric proclaimed.

“100% sure it’s a backend issue?,” the Big Boss asks to help give Eric an out.

“I only display what the backend returns. It must be what they are returning to me and not checking the user credentials,” Eric stated as the law of the universe. This recalled another joke of his: the front end is a pipe to the backend and the backend is the crap that the developers put into it.

“So you are positive that it’s a back end issue,” Big Boss asked.

“I mean I can even show you right now how to test it. If I’m sending different identities to the backend, then the backend should reply with different sets of data,” said Eric.

Eric grabbed the boss’s mouse and started clicking around on his computer. After a moment, he started shouldering the boss further away from his computer.

“Aha, See? It’s definitely different identities, but we see the same set of data, which as I’ve said is FROM THE BACKEND. You have to fix the backend, Gary,” Eric said.

Gary watched this, silently. He already knew exactly what was happening, and was just waiting to hang Eric out to dry. “Hey boss, can you try a couple things? Can you disable the browser cache and refresh the page?”

The Boss cleared and disabled the cache and refreshed. The Boss logged back in several more times, under different identities, and everything was correct. They re-enabled the cache, and the buggy behavior came back in. Clearly, the front-end was configured to aggressively cache on the client side, and Gary said as much.

“But it needs to be that way for performance…,” whined Eric. “Because the backend is so slow!”

“Well, it fixes the issue,“ the Big Boss said. ”So, Eric fix that front-end caching issue please."

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!


CodeSOD: Transport Layer Stupidity;

Keith H’s boss came by his cube.

“Hey, you know how our insurance quote site has TLS enabled by default?”

“Yes,” Keith said. The insurance quote site was a notoriously kludgy .NET 4.5.1 web app, with no sort of automated deployment and two parallel development streams: one tracked in Git, and one done by editing files and compiling right on the production server.

“Yes, well, we need to turn that off. ‘Compliance reasons’.”

This created a number of problems for Keith. There was no way to know for sure what code was in Git and what was in production and how they didn’t match. Worse, they relied on reCAPTCHA, which required TLS. So Keith couldn’t just turn it off globally, he needed to disable it for inbound client connections but enable it for outbound connections.

Which he did. And everything was fine, until someone used the “Save as PDF” function, which took the page on the screen and saved it as a PDF to the user’s machine.

protected void btnInvoke_Click(object sender, EventArgs e)
        {
            var url = util.getUrl("Quote", "QuoteLetterPDF.aspx");
            url = url + "?QuoteId=" + hdnCurrentQuoteId.Value;
            var pdfBytes = UtilityManager.ConvertURLToPDF(url);
            // send the PDF document as a response to the browser for download
            var response = HttpContext.Current.Response;
            response.Clear();
            response.AddHeader("Content-Type", "application/pdf");
            response.AddHeader("Content-Disposition",
                String.Format("attachment; filename=QuoteLetter.pdf; size={0}", pdfBytes.Length));
            response.BinaryWrite(pdfBytes);
            // Note: it is important to end the response, otherwise the ASP.NET
            // web page will render its content to PDF document stream
            response.End();
        }

public static byte[] ConvertURLToPDF(string url)
        {
            // ...redacted for brevity
            byte[] pdfBytes = null;
            var uri = new Uri(url);
            var encryptedParameters = Encrypt(uri.Query);
            var encryptedUrl = uri.Scheme + "://" + uri.Authority + uri.AbsolutePath + "?pid=" + encryptedParameters;
            var htmlData = GetHtmlStringFromUrl(encryptedUrl);
            pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(htmlData);
            return pdfBytes;
        }

 public static string GetHtmlStringFromUrl(string url)
        {
            string htmlData = string.Empty;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            System.Net.ServicePointManager.ServerCertificateValidationCallback =
        ((sender, certificate, chain, sslPolicyErrors) =>
        {
            return true;
        });
            var response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream receiveStream = response.GetResponseStream();
                    StreamReader readStream = null;
                    if (response.CharacterSet == null)
                    {
                        readStream = new StreamReader(receiveStream);
                    }
                    else
                    {
                        readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
                    }
                    htmlData = readStream.ReadToEnd();
                    response.Close();
                    readStream.Close();
                }
            return htmlData;
        }

It’s a lot of code here. btnInvoke_Click is the clearly named “save as PDF button” callback handler. What it does, using ConvertURLToPDF and GetHtmlStringFromUrl is… send a request to a different ASPX file in the same application. It downloads the HTML, and then passes the HTML off to a PDF converter which renders the HTML into a PDF.

For reasons which are unclear, it encrypts the parameters which it's passing in the query string. These requests never go across the network, and even if they did, it's generally more reasonable to pass those parameters in the request body, which would be encrypted via TLS.

And it does send this request using TLS! However, as Keith disabled support for incoming TLS requests, this doesn’t work.

Which is funny, because TLS being disabled is pretty much the only way in which this request could fail. An invalid certificate wouldn’t, because of this callback:

            System.Net.ServicePointManager.ServerCertificateValidationCallback =
        ((sender, certificate, chain, sslPolicyErrors) =>
        {
            return true;
        });

Keith re-enabled TLS throughout the application, “compliance” reasons be damned.

[Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!


CodeSOD: The National Integration;

Sergio works for a regional public administration. About a decade ago, the national government passed some laws or made some regulations, and then sent a software package to all the regional administrations. This software package was built to aggregate reports from the local databases into a single, unified, consistent interface on a national website.

Of course, each regional group did things their own way, so the national software package needed to be customized to work. Also, each regional administration had their own reporting package which already did some of this, and which they liked better, because they already knew how it worked. In the case of Sergio's employer, even more important: their organization's logo was prominently displayed.

Of course, there was also the plain old stubborness of an organization being told they have to do something when they really don't want to do that thing. In that situation, organizations have all the enthusiasm of a five year old being told to brush their teeth or eat their vegetables.

The end result was that the people tasked with doing the integration and customization didn't want to be doing that, and since the organization as a whole didn't want to do anything, they weren't exactly putting their top-tier resources on the project. The integration task was doled out to the people who literally couldn't be trusted to do anything else, but couldn't be fired.

Shockingly, national noticed a huge number of errors coming from their software, and after a few months of constant failures and outages, Sergio was finally tasked with cleaning up the mess.

private ReportsWSStub stub = null; public ReportHelper() { try { if (null == stub) { // URL del WS String url = InicializacionInformes.URL_WS_CLIENTE_INFORMES; System.out.println("URL " + url); stub = (ReportsWSStub)new ReportsWSStub(url); log.info("Report's 'stub' has been initialized"); log.info("URL for the Report's stub " + url); log.info("stub._getServiceClient() " + stub._getServiceClient()); ... } } catch (Exception e) { log.error(" Exception", e); System.out.println(" Exception" + e.getMessage()); } }

Here, we have the constructor for the ReportHelper class. It might be better named as a wrapper, since its entire job is to wrap around the ReportsWSStub object. It's important to note that this object is useless without a valid instance of ReportsWSStub.

With that in mind, there's all sorts of little things which pop out. First, note the if (null == stub) check. That's a backwards way to write that, which sort of sets the tone for the whole block. More than just backwards- it's pointless. This is the constructor. The stub variable was initialized to null (also unnecessary). The variable can't be anything but null right now.

Then we go on and mix log calls with System.out.println calls, which this is a JEE component running on a webserver, so those printlns fly off to the void- they're clearly left over debugging lines which shouldn't have been checked in.

The key problem in this code, however, is that while it logs the exception it gets when trying to initialize the stub, it doesn't do anything else. This means that stub could still be null at the end of the constructor. But this object is useless without a stub, which means you now have an unusuable object. At least it hopefully gives you good errors later?

public Report getReport(String id , String request) throws IOException { ... try { stub._getServiceClient().getOptions().setProperty( Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE); stub._getServiceClient().getOptions().setProperty( Constants.Configuration.CACHE_ATTACHMENTS, Constants.VALUE_TRUE); stub._getServiceClient().getOptions().setProperty( Constants.Configuration.FILE_SIZE_THRESHOLD, "10000"); stub._getServiceClient().getOptions() .setTimeOutInMilliSeconds(100000); stub._getServiceClient().getOptions().setProperty( org.apache.axis2.transport.http.HTTPConstants.CHUNKED, Boolean.FALSE); requestInforme.setGetReport(requestType); if(stub == null){ log.info("##################### Stub parameters are null!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } else { log.info("#####################Stub parameters are not null!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } responseInformes = stub.getReport(requestInforme); } catch (Exception e) { //... } }

As you can see, they've helpfully added a if (stub == null) check to see if stub is null, and log an appropriate message. And if stub isn't null, we have that else block to log a message stating that the parameters are not null, but with the same enthisuasm and exclamation points of the error. And of course, we're only trying to log that the stub is null, not, y'know, do anything different. "We know it's a problem, but we're doing absolutely nothing to change our behavior."

That's okay, though, because if stub is null, we'll never log that error anyway, because we'll get a NullReferenceException instead.

[Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!


Error'd: From Error to Disaster;

"They're a SEO company, so I'm pretty sure they know what they're doing," Björn E. wrote.

 

"When your toddler has to study for their ITIL certificate, the least you can do is give them a nice desk to study on," writes Sven V.

 

Esox L. wrote, "They claim to be in top 5%...but where would they be if they set name?"

 

"I guess you should never say 'never' when it comes to Microsoft Dynamics 365," writes Andrew.

 

Philip B. writes, "Say what you like, CNN, but there's the headline."

 

"So, wait, if all the images are for a single taxi...and the Google CAPTCHA is looking for taxis (plural)...you know, I must be robot or something," Peter G. wrote.

 

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!


CodeSOD: What For?;

Pretty much every language has many ways to do loops/iteration. for and while and foreach and do while and function application and recursion and…

It’s just too many. Mike inherited some code which cleans up this thicket of special cases for iteration and just uses one pattern to solve every iteration problem.

// snip. Preceding code correctly sets $searchArray as an array of strings.
$searchCount = count($searchArray);
if ($searchCount > 0) {
	$checked = 0;
	while ($checked != $searchCount) {
		$thisOne = $searchArray[$checked];
		// snip 86 lines of code 
		$checked++;
	}
}

Gone are the difficult choices, like “should I use a for or a foreach?” and instead, we have just a while loop. And that was the standard pattern, all through the codebase. while(true) useWhile();, as it were.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!