Software compatibility and our own “User-Agent” problem
sigbus.info
sigbus.info
Strange, or actually helpful? It would've been more devious if the message it was looking for actually contained more... potentially copyrightable content; here's one recently-mentioned example:
https://dacut.blogspot.ca/2008/03/oracle-poetry.html
This also reminds me of https://en.wikipedia.org/wiki/Sega_v._Accolade and https://en.wikipedia.org/wiki/Lexmark_International,_Inc._v.....
Anyone who has experimented with Hackintoshing may also recall the "SMCDeviceKey", a "magic cookie" that serves a similar purpose of attempting to use copyright as a blocker to compatibility.
When I first read the passage about libtool I thought it was a joke, and the illusion of order got a cold reality shower:
> the tests elaborately explore the functionality of the complex solution for a problem that should not exist in the first place. Even more maddening is that 31,085 of those lines are in a single unreadably ugly shell script called configure. The idea is that the configure script performs approximately 200 automated tests, so that the user is not burdened with configuring libtool manually. This is a horribly bad idea, already much criticized back in the 1980s when it appeared, as it allows source code to pretend to be portable behind the veneer of the configure script, rather than actually having the quality of portability to begin with.
With webpack, babel, TS, grunt, gulp, and all together, thousands of tools just glued together.
In the Java world, at least, every few years everyone rewrites the tooling from scratch, so wehad running javac by yourself be replaced by ant, ant by maven, maven by gradle. But, that's it.
In the JS world, you see nodejs launch a python script launch a ruby program launch a perl wrapper for a shell script launching another nodeJS process (e.g. during preprocessing of templates).
You end up with configs that are copy pasted because no one can exactly explain how all the tools work together, much less configure it.
In the C/C++ world everything got a bit better once we got CMake and Ninja, now CMake builds one file, which ninja then reads, and based on which it executes G++. Bazel/Blaze even removes this intermediate step entirely.
Sometimes there are npm packages that are just wrappers for other projects, but those are usually short-lived and end up being rewritten in JS (except for C/C++ libraries, which neatly compile to native extensions directly).
If anything, the common complaint is much more accurate: the tooling is rewritten from scratch too often.
How is that relevant?
The problem is still that you end up with tools wrapped around tools wrapped around tools.
Building a usual nodeJS project ends up with the callstack in my process explorer being 20 levels deep, of node processes, some bash mixed in, and inbetween ruby, python etc for building the documentation with mkdocs and the SASS or SCSS
Instead of precompiling Typescript and JSX to ES5, with Babel that to ES4, then launching dozens of asset processors to turn your SASS, SCSS, and JSS into CSS, with dozens of wrapped processes...
As mentioned, the Java world handles everything with 2 processes, the C++ world with 3.
Only the JS world manages to run in a single project webpack, gulp, grunt, compass, typescript, babel, and JSX, all transforming the source, leading to build times second only to old-school C++ projects.
In a universe of abundant open source these problems are sometimes stupid easy to solve. The x86Open project was a consortium to define a common ABI for Unix implementations on x86 hardware. But since all the vendors involved (including a couple of open-source BSDs) already shipped Linux kernel personalities for their OS, the only business x86Open ever did was to declare "Linux ELF binaries" the standard and then disband itself.
I don't know autoconf and this sentence got me curious: why would it not be possible to regenerate existing configure scripts using a fixed version of autoconf? Are those scripts likely to be manually edited after they've been generated?
Indeed, the latest release of libtool is 2.4.6, from February 2015 (more than two years ago).
If you were creating a new class of software where this could be an issue, what would you do?
The problem is when you can't get everybody to agree on a standard API, so you resort to hacks that make it work ASAP that then lead to more and more hacks till we get the insane user agents of today.
> The solution we ended up choosing was to add the string "compatible with GNU linkers" to our linker's help message.
The right way to deal with things like this is to do both. Do the hacky-but-realistically-shippable thing to get unblocked, and then also contribute towards the "right" solution, even if it's way upstream from you. Otherwise you're part of the problem.
You young 'uns may not remember it, but there used to be more systems than Windows, Mac, and Linux, and forced OS updates weren't a thing. Libtool was a way to try to make programs run on most people's computers, by compiling small programs to detect individual features. It was written in a nightmare language called M4, which would generate shell scripts, which would usually generate C programs, which would attempt to compile and run.
I typically do not use libtool but rather have an autoconf macro [0] to determine how to interact with the linker. This has the disadvantage that each "./configure" invocation can only produce either static or shared archives, but not both (since the object files that make those up may require different compile flags). libtool's solution is to compile the object file both ways, but it does not really go well with the autoconf mechanism.
I also have a different set of macros for managing the ABI [1], and I'm not sure how that's managed with libtool.
[0] http://chiselapp.com/user/rkeene/repository/autoconf/artifac... [1] http://chiselapp.com/user/rkeene/repository/autoconf/artifac...
Lying about the VH is violating standards and should be handled as such. An electrician does not think "but what if the customer suddenly changes their house voltage from 210V to 123V" but rather "anybody doing that is insane and I'm not going to be responsible if they do that".
The fact that we have to do this is a testament to how bad the standards situation has been in the past and still is.
The proper way would be to have one function that every browser supports and which you can ask about such specifics. Writing browser.is-doing("vh-lying") instead of having to work around the idiocracy of the browser in other ways is inarguably better.
EG: www/HTML<=5.1 www/XHTML<=1.1 www/CSS<=3.0 ISO/ECMAScript<=8
The string would be split on the field separator (any non-printing space?). All exact matches for specifications would be compared and the result ANDed. This way a range could be created by having a minimum supported version as well.
I remember back when feature detection was gaining steam as the preferred alternative to user-agent sniffing, and Safari had a showstopper of a bug that meant preventDefault was present and callable but didn't actually do what preventDefault was supposed to do. So you had to fall back to sniffing for Safari to work around that (by hooking up a different event listener with a 'return false' instead of a preventDefault call).
Alas, people don't do that in business.
I'd much rather if the "version number" of the browser wasn't exposed, and instead something like a UUID that changes every "major version" for each browser.
This lets developers blacklist specific browser versions if they are a problem, without allowing them to say "only works on chrome" or "fallback to this on safari at any version".
I know this would be basically impossible to get everyone to agree on, but it's an interesting thought.
It's not about making it impossible, it's about making it difficult enough that the "easy path" is feature detection (AKA "doing it right")
But by changing how the useragent works I think we can get rid of the vast majority who only do useragent sniffing because it's the "easy way out", it's the quick fix that will let them get back to development instead of fixing a bug or shimming a feature.
If you have Flash installed, but the site is not whitelisted, Chromium will claim Flash is not installed to any JS detection code.
At ~/.dillo/dillorc
http_user_agent="Opera/9.60 (J2ME/MIDP; Opera Mini/4.2.13337/458; U; en) Presto/2.2.0"
Why anyone thinks it's a good idea not to send API data to a python User-Agent is kind of beyond me but who knows...can't really complain since they provide data for free and I really was just playing around without actually needing to do anything productive.
Actually found a bug in urllib3 (that I probably should get around to reporting) -- page sends http unless you set Accept to 'application/json' which urllib3 doesn't let you do.
import urllib.request as rq
req = rq.Request(url, headers={'User-Agent': useragent})
request = rq.urlopen(req, timeout=timeout)
You should be able to set Accept in a similar fashion (tho IDK if urllib mandates a certain value for that header).IIRC 'User-Agent' wasn't the problem but trying to set 'Accept' is what failed (and even more strangely they only do User-Agent filtering on API calls but not for http). I started to dig into the code but since I got it to work in urllib I left it as Someone Else's Problem.
http = urllib3.PoolManager()
r = http.request('GET', "https://oneom.tk/data/config", headers={'Accept': 'application/json', 'User-Agent' : "Mozilla/5.0"})
r.headers['Content-Type'] 'application/json'
r = http.request('GET', "https://oneom.tk/data/config", headers={'Accept': 'application/json'})
r.headers['Content-Type'] 'text/html; charset=UTF-8'
You can reproduce with curl with the following command:
curl -v 'https://oneom.tk/data/config' -H 'Accept: application/json' -H 'User-Agent:'
That'll nullify the default curl user agent and should produce the same results you were seeing with urllib3.When I was messing with it I could get it to work with curl and (eventually) urllib but urllib3 was no bueno until I tried to reproduce the problem and just copied the header with the User-Agent field from the urllib code.