Re: Help choosing the most efficient, dependable condition(al)
by daxim (Curate) on Nov 13, 2013 at 19:02 UTC
|
That regex match is wrong. HTTP defines how you must negotiate a content type. Correct code:
use strictures;
use HTTP::Negotiate qw(choose);
# play with the quality
# values here ↓
# ↓
# ↓
if ('xhtml' eq choose([
[ xhtml => 1 => 'application/xhtml+xml' ],
[ html => 1 => 'text/html' ]
])) {
print "Content-Type: application/xhtml+xml; charset=UTF-8\n";
} else {
print "Content-Type: text/html; charset=UTF-8\n";
}
print "Vary: Accept\n"; # tell caches this resource has several representations
demo:
HTTP_ACCEPT='text/html; q=0.5, application/xhtml+xml; q=0.2' perl pm1062426.pl
HTTP_ACCEPT='text/html; q=0.5, application/xhtml+xml; q=0.8' perl pm1062426.pl
HTTP_ACCEPT='text/html, application/xhtml+xml' perl pm1062426.pl
HTTP_ACCEPT='text/html' perl pm1062426.pl
HTTP_ACCEPT='text/html, text/plain; q=0.5' perl pm1062426.pl
HTTP_ACCEPT='application/xhtml+xml' perl pm1062426.pl
HTTP_ACCEPT='application/xhtml+xml, application/xml, text/html, text/plain; q=0.1' perl pm1062426.pl
Update: add the Vary header, fix a header syntax error in demo line 5 | [reply] |
|
|
Greetings daxim, and thank you very much for all the time, and effort you put into this.
You're test seem conclusive. But isn't using/requiring a Module a bit overkill?
I mean, doesn't perl already provide sufficient method(s) to accomplish such goals?
Maybe I'm wrong. But having used the method I posted here for some 2 years now. I haven't seen any evidence that there were any issues with it, except to the extent that an occasional "Use of uninitialized value $ENV{"HTTP_ACCEPT"}" would show up in the error log(s).
I'm not trying to say that method is right. I'm just (while impressive) not sure that doing it correctly requires using an extra Module
Thank you again daxim for all your time, and effort on this.
--Chris
#!/usr/bin/perl -Tw
use Perl::Always or die;
my $perl_version = (5.12.5);
print $perl_version;
| [reply] |
|
|
But isn't using/requiring a Module a bit overkill?
HTTP::Negotiate has passed smoke testing on 4244 systems, and failed on one, which was probably misconfigured. Those systems include Perl versions from 5.8.1 through 5.19.6, on operating systems including Window (cygwin), Mac, DragonflyBSD, FreeBSD, GNU Hurd, Debian, Haiku, GNU Linux, MidnightBSD, MirOS BSD, Win32, NetBSD, QNX Neutrino, OpenBSD, and Sun/Solaris. It is used in production, probably in many instances. Its test suite, while minimal, exists, and works.
HTTP::Negotiate "...provides a complete implementation of the HTTP content negotiation algorithm specified in draft-ietf-http-v11-spec-00.ps chapter 12." And it's been around since 1996. It currently has one bug report in its RT, relating to a typo in the POD. It has POD.
You have an if statement with a fragile regular expression. ...I'm sorry, what was your question again? ;)
I mean, doesn't perl already provide sufficient method(s) to accomplish such goals?
Yes. HTTP::Negotiate is written in pure-Perl. Perl is capable of facilitating the implementation of standards compliant HTTP negotiation. Your code doesn't do that.
When the phone rings, I want to pick up a device that I can push the "answer" button on, hold to my ear, and hear the caller's voice. I don't want to pick up a heap of wires and chips on a breadboard and hold my hand to a grounding plate with a crystal earphone from radio shack in my ear. Well, maybe if I'm in a "hobby" mood I do. But when I want it to work reliably, I use the well tested, well engineered device, not the cobbled apparatus.
Programmers love to program, just like salespeople love to talk. Sometimes we have to temper that with a splash of Perlish lazyness.
| [reply] [d/l] |
|
|
|
|
But isn't using/requiring a Module a bit overkill?
No. This kind of thinking is exactly what makes maintaining old code such a burden.
I mean, doesn't perl already provide sufficient method(s) to accomplish such goals?
So does C, and COBOL, and Assembly. Dovetailed with the above we get: Isn’t using a high level language overkill?
| [reply] |
|
|
|
|
|
|
|
thank you very much for all the time, and effort you put into this.
Thank the libwww-perl authors, they did all the hard work of translating the algorithm into code and releasing it. I just remembered that this module exists, and adapted its documentation synopsis for your circumstance.
But isn't using/requiring a Module a bit overkill?
No. It does exactly what it needs to do, no less, barely more. You would not save much memory if you were to reimplement it from scratch.
doesn't perl already provide sufficient method(s) to accomplish such goals?
No, there is no negotiate function baked into Perl, being a general-purpose language. Maybe PHP has it, that would make sense given its Web deployment niche.
having used the method I posted here for some 2 years now. I haven't seen any evidence that there were any issues with it
This is not rational. Past evidence makes no promise about future performance. I can easily construct a case where the naive regex match breaks down, and the case wouldn't even be degenerate. Hint: that match ignores the q value.
In any case, this is not how a specification works. As part of the Internet, you have entered into this consensus/social contract to follow the specs. Either you are compliant, and gain interoperability, or you don't follow it, and the rest of the Internet treats you as RFC-ignorant/damage and routes around. Don't be that guy who does it on purpose, there's enough trouble already with unintentional bugs. (I had a bug in the code I showed thread-upwards, see the update.)
doing it correctly requires using an extra Module
It's free software, you can just copy the code into your project, so you have the functionality, but not a module. I generally don't do so because that approach harder to maintain. I like the abstraction modules gives me, and Perl's dependency management is outstanding. Why are you uneay about using a module as it is? Where do you draw the line what's acceptable and what not?
| [reply] |
|
|
|
|
# your version
print "Content-Type: application/xhtml+xml; charset=UTF-8\n";
} else {
print "Content-Type: text/html; charset=UTF-8\n";
# MY version
print "Content-Type: application/xhtml+xml; charset=UTF-8\n\n";
} else {
print "Content-Type: text/html; charset=UTF-8\n\n";
For the record; it takes 2 newlines (\n\n). :)
--Chris
#!/usr/bin/perl -Tw
use Perl::Always or die;
my $perl_version = (5.12.5);
print $perl_version;
| [reply] [d/l] |
|
|
Not if send another header, namely "Vary". See the code update in Re: Help choosing the most efficient, dependable condition(al)
There's a lot to be gained by using a Web framework (you are familiar with CGI.pm, try Plack::Request/Plack::Response), where one doesn't have to care about newlines at all - the software handles the correct formatting for me. Short example: plackup -MPlack::Request -e'sub { my $req = Plack::Request->new(shift); return $req->new_response(200, [Content_Type => "text/html", Vary => "Accept"], [])->finalize }'
Doing the formatting manually and needing to get it correct is the real overhead. The work time of a programmer is expensive.
| [reply] [d/l] |
|
|
Re: Help choosing the most efficient, dependable condition(al)
by kcott (Archbishop) on Nov 13, 2013 at 18:56 UTC
|
G'day Chris,
I may be missing something here; apologies in advance if I have. I've looked at this several times and both appear to be using the same logic just written differently:
if X then Y else Z
unless X then Z else Y
Is it me or you? :-)
| [reply] [d/l] |
|
|
Greetings kcott, and thank you for taking the time to respond.
It's me. I'm sure of it.
Which is why I came here to ask. :)
OTOH I've used this method for at least a couple of years now. With the exception of an occasional "Use of uninitialized value $ENV{"HTTP_ACCEPT"}...". I can't see any issue(s).
But that doesn't mean it's correct.
Thanks again, for taking the time to respond.
--Chris
#!/usr/bin/perl -Tw
use Perl::Always or die;
my $perl_version = (5.12.5);
print $perl_version;
| [reply] |
|
|
The point I was making is that what you've "been using", and what you're considering "might be a better choice", use identical logic: the logic is written differently but both achieve the same result.
I've looked long at the condition and TRUE/FALSE code in both but can't see any difference.
It's possible I'm missing something: if not, then your not really changing anything and perhaps there's a typo in your posted code.
| [reply] |
|
|
|
|
Re: Help choosing the most efficient, dependable condition(al)
by locked_user sundialsvc4 (Abbot) on Nov 13, 2013 at 20:43 UTC
|
Without trying to dumpster-dive into this particular debate, I would note that it is easy to avoid messages like “use of uninitialized value” through the use of the && (logical-AND) operator, which uses so-called short circuit evaluation: if the left-hand side is False, the right-hand side is not evaluated at all. (See perldoc perlop.)
Thus, you can say (say...):
if ( $ENV{'HTTP_ACCEPT'} && ( $ENV{'HTTP_ACCEPT'} =~ ...
undef is always False. So, the statement quits right there and the remainder of the expression is never evaluated.
| |
|
|
if (($ENV{'HTTP_ACCEPT'} || '') =~ /application\/xhtml\+xml/)
{
print "content-type:application/xhtml+xml; charset=utf-8\n\n";
}else{
print "content-type:text/html; charset=utf-8\n\n";
}
It helps to remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
| [reply] [d/l] |