Saturday, April 16, 2016

Debian: disabling SSLv3 in courier server

Debian wheezy (currently oldstable) ships courier-0.68 which was probably released on 2012.
“Probably”, because, head over to the Courier website and try to find the NEWS/ChangeLog.

The Problem

Anyway. Courier-0.68 has built-in openssl support on Debian and it initializes a SSL context the following way:

        ctx=SSL_CTX_new(protocol && strcmp(protocol, "SSL3") == 0
                        ? SSLv3_method():
                        protocol && strcmp(protocol, "SSL23") == 0
                        ? SSLv23_method():
                        TLSv1_method());

        // ...
        SSL_CTX_set_options(ctx, SSL_OP_ALL);

        if (!ssl_cipher_list)
                ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";

        SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
 
Some clarifications:
  • SSLv3_method would only allow SSLv3
  • TLSv1_method would only allow TLSv1.0
  • SSLv23_method is “the general-purpose version-flexible SSL/TLS method”

So, if we do not want to limit ourselves to TLSv1.0, i.e. allow TLSv1.0, TLSv1.1 and TLSv1.2, we have to limit our protocol version support through other means.

Openssl-1.0.1 (remember, we’re on Debian wheezy) does neither come with TLS_method() the generic TLS-only method, nor does it come with SSL_CTX_set_min_proto_version and we cannot disable SSLv3 with the cipher list if we also want to allow TLSv1.0.

Solution 1: Upgrading to Jessie

What if we upgrade to Debian jessie (current stable)? Jessie ships courier-0.73, so let’s see how SSL context intitialization looks there:

        options=SSL_OP_ALL;

        method=((!protocol || !*protocol)
                ? NULL:
                strcmp(protocol, "SSL3") == 0
                        ? SSLv3_method():
                strcmp(protocol, "SSL23") == 0
                        ? SSLv23_method():
                strcmp(protocol, "TLSv1") == 0
                ? TLSv1_method():
#ifdef HAVE_TLSV1_1_METHOD
                strcmp(protocol, "TLSv1.1") == 0
                ? TLSv1_1_method():
#endif
#ifdef HAVE_TLSV1_2_METHOD
                strcmp(protocol, "TLSv1.2") == 0
                ? TLSv1_2_method():
#endif
                NULL);

        if (!method)
        {
                method=SSLv23_method();
                options|=SSL_OP_NO_SSLv2;
        }

        ctx=SSL_CTX_new(method);

        // ...
        SSL_CTX_set_options(ctx, options);

        if (!ssl_cipher_list)
                ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";

        SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
 
Jessie also comes with openssl-1.0.1, so the situation would not improve for our undertaking by upgrading to jessie.

Solution 2: Augmenting SSL_CTX_new

What I came up with, is augmenting SSL_CTX_new and setting the desired SSL_OP_NO_SSLv3 on each newly created SSL context.

#include <stdio.h>
#include <dlfcn.h>
#include <openssl/ssl.h>

static void *lib;
static void *new_sym;
static void *opt_sym;

static void dl() {
        char *error;

        if (!lib) {
                lib = dlopen("libssl.so", RTLD_LAZY|RTLD_LOCAL);
                if (!lib) {
                        fprintf(stderr, "dlopen: %s\n", dlerror());
                        exit(1);
                }   
                dlerror();
        }   

        if (!new_sym) {
                *(void **) &new_sym = dlsym(lib, "SSL_CTX_new");
                if ((error = dlerror())) {
                        fprintf(stderr, "dlsym: %s\n", error);
                        dlclose(lib);
                        exit(1);
                }   
        }   

        if (!opt_sym) {
                *(void **) &opt_sym = dlsym(lib, "SSL_CTX_ctrl");
                if ((error = dlerror())) {
                        fprintf(stderr, "dlsym: %s\n", error);
                        dlclose(lib);
                        exit(1);
                }   
        }   
}

SSL_CTX *SSL_CTX_new(const SSL_METHOD *m) 
{
        SSL_CTX *ctx;

        dl();

        ctx = ((SSL_CTX *(*)(const SSL_METHOD*))new_sym)(m);

        if (ctx) {
                ((long (*)(SSL_CTX *, int, long, void*))opt_sym)(ctx, SSL_CTRL_OPTIONS, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3, NULL);
        }   
        return ctx;
}
 
This is the source of a tiny shared library pre-defining our SSL_CTX_new; to build like e.g.
gcc -ldl -fPIC -shared -o preload.so preload.c

It does the following:
  • augments SSL_CTX_new with our own version, i.e. whenever courier calls SSL_CTX_new our own version gets called
  • when it’s called the first time, it
    • dlopen’s libssl
    • fetches the addresses of the original SSL_CTX_new and SSL_CTX_ctrl (which is the actual function SSL_CTX_set_options calls)
  • calls the original SSL_CTX_new to actually create the SSL context
  • calls SSL_CTX_ctrl on the new context with the options we want to set (SSL_OP_NO_SSLv3)
  • returns the context to the caller

Usage

Courier config files are basically shell scripts which set a environment variables, so we’ll enable it as follows:

cd /etc/courier
cat >>esmtpd >>esmtpd-msa >>esmtpd-ssl \
    >>pop3d >>pop3d-ssl \
    >>imapd >>imapd-ssl \
    >>courierd <<EOF
LD_PRELOAD=/path/to/preload.so
EOF
 
Then restart each courier service.

Verifying

Last, we have to verify that our solution actually works:
openssl s_client -CApath /etc/ssl/certs/ -starttls imap -connect localhost:143 -crlf -quiet -ssl3 <<<LOGOUT
139690858608296:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1261:SSL alert number 40
139690858608296:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:599:
A bunch of errors. “Good”! :)
Let’s see if we can still connect with TLSv1+:
openssl s_client -CApath /etc/ssl/certs/ -starttls imap -connect localhost:143 -crlf -quiet -tls1 <<<LOGOUT
depth=2 ...
verify return:1
depth=1 ...
verify return:1
depth=0 ...
verify return:1
. OK CAPABILITY completed
* BYE Courier-IMAP server shutting down
LOGOUT OK LOGOUT completed
Awesome. Mission accomplished.

Addendum

Here’s my cipher list for the interested:
openssl ciphers -v 'HIGH+aRSA:+kEDH:+kRSA:+SHA:+3DES:!kSRP' \
  | awk '{ printf "%-28s %-8s %-8s %-18s %-16s\n",$1,$2,$3,$5,$6 }'
Which results in the following ciphers:
ECDHE-RSA-AES256-GCM-SHA384  TLSv1.2  Kx=ECDH  Enc=AESGCM(256)    Mac=AEAD
ECDHE-RSA-AES256-SHA384      TLSv1.2  Kx=ECDH  Enc=AES(256)       Mac=SHA384
ECDHE-RSA-AES128-GCM-SHA256  TLSv1.2  Kx=ECDH  Enc=AESGCM(128)    Mac=AEAD
ECDHE-RSA-AES128-SHA256      TLSv1.2  Kx=ECDH  Enc=AES(128)       Mac=SHA256
DHE-RSA-AES256-GCM-SHA384    TLSv1.2  Kx=DH    Enc=AESGCM(256)    Mac=AEAD
DHE-RSA-AES256-SHA256        TLSv1.2  Kx=DH    Enc=AES(256)       Mac=SHA256
DHE-RSA-AES128-GCM-SHA256    TLSv1.2  Kx=DH    Enc=AESGCM(128)    Mac=AEAD
DHE-RSA-AES128-SHA256        TLSv1.2  Kx=DH    Enc=AES(128)       Mac=SHA256
AES256-GCM-SHA384            TLSv1.2  Kx=RSA   Enc=AESGCM(256)    Mac=AEAD
AES256-SHA256                TLSv1.2  Kx=RSA   Enc=AES(256)       Mac=SHA256
AES128-GCM-SHA256            TLSv1.2  Kx=RSA   Enc=AESGCM(128)    Mac=AEAD
AES128-SHA256                TLSv1.2  Kx=RSA   Enc=AES(128)       Mac=SHA256
ECDHE-RSA-AES256-SHA         SSLv3    Kx=ECDH  Enc=AES(256)       Mac=SHA1
ECDHE-RSA-AES128-SHA         SSLv3    Kx=ECDH  Enc=AES(128)       Mac=SHA1
DHE-RSA-AES256-SHA           SSLv3    Kx=DH    Enc=AES(256)       Mac=SHA1
DHE-RSA-CAMELLIA256-SHA      SSLv3    Kx=DH    Enc=Camellia(256)  Mac=SHA1
DHE-RSA-AES128-SHA           SSLv3    Kx=DH    Enc=AES(128)       Mac=SHA1
DHE-RSA-CAMELLIA128-SHA      SSLv3    Kx=DH    Enc=Camellia(128)  Mac=SHA1
AES256-SHA                   SSLv3    Kx=RSA   Enc=AES(256)       Mac=SHA1
CAMELLIA256-SHA              SSLv3    Kx=RSA   Enc=Camellia(256)  Mac=SHA1
AES128-SHA                   SSLv3    Kx=RSA   Enc=AES(128)       Mac=SHA1
CAMELLIA128-SHA              SSLv3    Kx=RSA   Enc=Camellia(128)  Mac=SHA1
ECDHE-RSA-DES-CBC3-SHA       SSLv3    Kx=ECDH  Enc=3DES(168)      Mac=SHA1
EDH-RSA-DES-CBC3-SHA         SSLv3    Kx=DH    Enc=3DES(168)      Mac=SHA1
DES-CBC3-SHA                 SSLv3    Kx=RSA   Enc=3DES(168)      Mac=SHA1
 
Note, that courier actually does not support ECDH key exchange, but I didn’t exclude it for the sake of simplicity for using the same cipher list for every server (e.g. web etc.)

Wednesday, August 19, 2015

Blank DELL on DisplayPort

I've been struggling since ever with my DELL U3014 on the DisplayPort saying there's no signal after a power cycle of the monitor.

I just found a solution to bring the monitor back to life without rebooting the box; just ssh into and issue:

$ DISPLAY=:0 xset dpms force off
$ DISPLAY=:0 xset dpms force on

I'm running Gnome3 on Arch Linux, so YMMV.

Tuesday, August 11, 2015

Testing PHP extensions on Travis-CI

Testing PECL extensions on Travis-CI has always been cumbersome for me; build PHP in different versions and debug/threadsafe flavors, install PECL dependencies and so on, which usually results in a mess of command line scripts, repeated for every extension.

Enter travis-pecl.

This tiny support bin comes with a Makefile and small PHP scripts to generate the build matrix and check your package.xml file. It supports building PHP in a wide variety of flavors, installing PECL dependencies from the PECL website or from bundled pharext packages and running the testsuite with a comprehensive set of commands.

Let's look at a few commands with a properly set up environment from the test matrix:

env:
 - PHP=5.6 enable_debug=yes with_iconv=yes enable_json=yes

Build PHP:

make -f travis/pecl/Makefile php

Install a PECL dependency:

make -f travis/pecl/Makefile pecl PECL=propro

Install a PECL dependency from a pharext package, located in travis/:

make -f travis/pecl/Makefile pharext/raphf-phpng

Build the currently checked out extension;

make -f travis/pecl/Makefile ext PECL=http

Run the testsuite:

make -f travis/pecl/Makefile test


Finally, check out the README and have a look at a couple of complete examples here:

Monday, December 9, 2013

Evolution of $

Today I realized an important and probably very obvious fact: we all change. Of course, you will say. Surely most of us will agree to that, but the important thing about that is also realizing that we drift away from things we loved. Okay, so what am I actually talking about? :)

I talk about software development, specifically development of and with PHP. We've seen some radical proposals in the nearer past and in deed are still seeing those for PHP, the language. Often, I was inclined to think "cool, that's a great idea, let's improve in that direction."

PHP was and is a huge success, it attracts a lot of awesome people, sometimes becoming unhappy with the language's principles and resulting limitiations, like its simplicity, its forgiving nature and the enigne's effort to come to an end for this request, i.e. to die. Looking at the larger frameworks which have evolved the last few years, they head into a clear direction: strictly object oriented programming with RidiculouslyLongClassNamesLikeFoundInOtherStrictlyObjectOrientedLanguages. Anything non object oriented seems to be verboten. But this is not of what PHP was meant to be and it is very hard to change something that late in the game in such drastical ways. I don't think PHP can change as fast as we do, it's actually much longer around than most of us call ourself programmers.

What I mean to say is, don't be angry with PHP the language, don't force it to change in a way it's not supposed to survive, stop proposing language level changes in a weekly manner, don't be afraid to change yourself. Don't be afraid to advance yourself. Don't be afraid to change the language you program in. BOOM, I said it. Yes, don't be afraid to explore other possibilities that better support your principles instead of fighting them.

I'm not saying go away, I'm saying go ahead, or at least I mean to.

Sorry for the fast write-up, all the typos and errors. Have a nice start into your week!

Tuesday, June 18, 2013

Hear, hear

I was about to write "in early February" but actually it already was in late January that I stumbled over this tweet:

Fast-forward five months – now I am very excited to be able to announce that the Awesomes over at SmugMug, Inc. have hired me to work full-time on the core of PHP.

Hide bugs.php.net, expect massive amounts of commits, sleep well. Thank you for reading the simple words of the proudest man alive. Thank you SmugMug!

Sunday, March 3, 2013

pecl_http-1.7.5

pecl_http-1.7.5 has been released today.
Nearly a year and 170k downloads after the last release (1.7.4 was released April 2nd 2012).

It fixes a single bug:
  • Bug #64310 (weak etags W/"abc" are quoted as "W/"abc"")

The same user (thanks Niko), discovered a peculiarity of libcurl:
  • If you utilize libcurl's TIMECOND feature through pecl_http's lastmodified request option, libcurl ignores response bodies from servers that do not closely follow the RFC and send a 200 OK response instead of a 304 Not Modified when the condition is unmet.
Slightly more background information is available at the relevant bug report.

Please leave a comment, if you have an opinion about which component's behavior is arguable here.

Tuesday, February 19, 2013

pecl_http-v2 - http2 or httpi or http-*

I'm pondering to release v2 of pecl_http with a different extension name than "http", but I cannot agree with myself what's worse:

http2

This might be confused with HTTP/2.0

httpi

There's mysqli following this approach, but I think this is pretty odd.

Split it up

Split the package up in several smaller sub-packages, like:
  • http-common
  • http-env
  • http-client
  • http-client-curl
  • etc.
If you have an opinion, or maybe even a better idea, please leave a comment.

Friday, March 18, 2011

Javascript delaying

In need of executing Javascript after the page has loaded, or something else has been initialized I came up with a simple but useful tiny "Delayer":



/**
* @param handler a callback accepting Delayer.dispatch as argument
*/
function Delayer(handler) {
var self = this;

this.dispatch = function() {
for (var i = 0; i < self.length; ++i) {
console.log("running delayed init "+i+": "+self[i]);
self[i]();
}
};

if (typeof handler == "function" || handler instanceof Function) {
handler(this.dispatch);
}
}

Delayer.prototype = Array.prototype;

It can be initialized the following way:



/* e.g. with jQuery */
window.delayedInits = new Delayer($(document).ready);
/* e.g. with Facebook */
window.fbDelayedInits = new Delayer(function(dp){window.fbAsyncInit = dp;});

Then you push your work the usual way:



delayedInits.push(function() {alert("Hello, delayed!");});

Monday, March 14, 2011

courier imap, authdaemond and vpopmails vchkpw

A few years ago, it was possible to have courier-imap update the open-smtp relay file with it's authvchkpw module. This feature and thus imap-before-smtp disappeared with the introduction of courier-authdaemond because the vchkpw code of authdaemond does not have a chance to see the TCPREMOTEIP environment variable.


I more or less lived with that, until a friend of mine got a new iphone... well yeah, one of those i-geeks, and that gadget apparently only supports imap, no pop.


To re-enable imap-before-smtp I wrote a little setuid wrapper, calling vpopmails open_smtp_relay(). This wrapper has to replace the imapd command in your courier-imap startup script and will exec imapd, after opening the smtp relay, wile imap-login is still in place to authenticate via authdaemond's vchkpw module.



#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>

#ifndef IMAPD
# define IMAPD "/usr/bin/imapd"
#endif

extern char **environ;

int main(int argc, const char *argv[]) {
if (argc != 2) {
printf("1 NO argc != 2n");
return -1;
}

open_smtp_relay();
/* no need to chown vpopmail.vchkpw the open-smtp file
* because vchkpw used by qmail-pop3d is setuid root */

sleep(1);

if (setgid(VPOPMAILGID) || setuid(VPOPMAILUID)) {
printf("1 NO setuid/gid, getuid=%dn", getuid());
return -2;
}

execl(IMAPD, IMAPD, argv[1], NULL);

printf("1 NO exec %s failedn", IMAPD);
return -3;
}

So while this worked to my satisfaction, I noticed that the tcp.smtp.cdb not always contained the IPs of the open-smtp file:



$ for ip in $(sed -re 's/:.*//' < open-smtp); do
cdbget $ip < tcp.smtp.cdb > /dev/null
|| echo "$ip is missing";
done

I also found out that, while the vpopmail FAQ is claiming that clearopensmtp is requesting locks on the open-smtp(.lock) file, the source does not read like it would.
I opened a bug report for that issue, but as you might have already guessed, I'm running all of this on an archaic debian box, where no upgrades are planned. So I came up with another home-brewed solution:



#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <vpopmail_config.h>
#include <vauth.h>
#include <vpopmail.h>
#include <fcntl.h>

extern int get_write_lock(FILE*);
extern int lock_reg(int,int,int,off_t,int,off_t);
#define unlock(F) lock_reg(fileno(F), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)

int main(int argc, const char *argv[]) {
FILE *fs_temp, *fs_smtp, *fs_lock = fopen(OPEN_SMTP_LOK_FILE, "w+");
time_t clear = RELAY_CLEAR_MINUTES * 60, now = time(NULL);
int cc = 0, rc = 0;

if (!fs_lock) {
return -1;
}
if (get_write_lock(fs_lock)) {
unlock(fs_lock);
fclose(fs_lock);
return -2;
}

if (!(fs_temp = fopen(OPEN_SMTP_TMP_FILE ".clear", "w"))) {
rc = -3;
} else if (!(fs_smtp = fopen(OPEN_SMTP_CUR_FILE, "r+"))) {
fclose(fs_temp);
rc = -4;
} else {
while (!rc && !feof(fs_smtp)) {
unsigned stime;
char sdata[256];

switch (fscanf(fs_smtp, "%255st%un", sdata, &stime)) {
case 2:
if ((clear + stime) >= now) {
fprintf(fs_temp, "%st%un", sdata, stime);
} else {
++cc;
}
break;

default:
rc = -5;
case EOF:
break;
}
}
fclose(fs_smtp);
fclose(fs_temp);
}

if (!rc) {
if (cc) {
if (rename(OPEN_SMTP_TMP_FILE ".clear", OPEN_SMTP_CUR_FILE)) {
rc = -6;
} else if(update_rules()) {
rc = -7;
}
} else {
unlink(OPEN_SMTP_TMP_FILE ".clear");
}
}

unlock(fs_lock);
fclose(fs_lock);
return rc;
}

It's not the prettiest piece of code, but it helps.
Well, maybe someone else running last-millenium software finds this useful

Monday, May 10, 2010

WebSockets Handshake non HTTP conforming?

Update:


Just found a revelatory discussion. The summary of Bjoern Hoehrmann is especially interesting with regards to that topic.




While skimming through the new HTML5 WebSocket draft, I noticed the following exemplar HTTP message demonstrating the client message of a WebSocket handshake:



GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com

^n:ds[4U

To me this looks non conforming to the HTTP spec due to the lack of an indicator that the request contains a message body.


Quoting the 4th paragraph of section 4.3 of RFC2616:


The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers. A message-body MUST NOT be included in a request if the specification of the request method (section 5.1.1) does not allow sending an entity-body in requests. A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.


Huh?

Monday, April 20, 2009

Looking for PHP Geeks in Austria

You guessed. I'm desperately looking for decent PHP Coders in Vienna, Austria.


The job posting (in german) can be found here:
http://www.inqnet.at/job09.html


Just ping me if you're interested in an face-to-face interview.

Friday, April 10, 2009

Friday, December 5, 2008

pecl_http and sub-second timeouts

Just a quick info, because I forget this again and again--and it's not noted in the documentation yet either.


Sub-second timeouts are supported by libcurl and thus by pecl_http--yes but only if libcurl is built with (c-)ares support:


<quote url="curl_easy_setopt.html">


If libcurl is built to use the standard system name resolver, that portion of the transfer will still use full-second resolution for timeouts with a minimum timeout allowed of one second.



</quote>

Tuesday, November 18, 2008

Vpopmail and people reaching their maildir quota

This tiny program lists all users of a domain with a maildir quota usage above 90%.



#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pwd.h>
#include <errno.h>

#include <vpopmail.h>
#include <vauth.h>

int main(int argc, char **argv) {
struct vqpasswd *user;
char dir[1024];
uid_t uid;
gid_t gid;
int offset_counter = -1, sort = 1, usage;

if (argc != 2) {
fprintf(stderr, "Usage: %s <domain>n", argv[0]);
return EXIT_FAILURE;
}
if (vget_assign(argv[1], NULL, 0, &uid, &gid) == NULL) {
fprintf(stderr, "domain '%s' does not existn", argv[1]);
return EXIT_FAILURE;
}
if (setgid(gid) || setuid(uid)) {
fprintf(stderr, "could not setuid/setgid to %d:%dn", uid, gid);
return EXIT_FAILURE;
}

while (NULL != (user = vauth_getall(argv[1], !++offset_counter, sort))) {
if (strcmp(user->pw_shell, "NOQUOTA")) {
snprintf(dir, sizeof(dir), "%s/Maildir", user->pw_dir);
usage = vmaildir_readquota(dir,
format_maildirquota(user->pw_shell));

if (usage >= 90) {
printf("%s %s %dn", user->pw_name, user->pw_shell, usage);
}
}
}

return EXIT_SUCCESS;
}

Qmail + SpamAssassin + selectivity

Here's how my qmail-queue script looks like to selectively check messages with SpamAssassin for non-relay clients only:



#!/bin/sh
(if [ -n "${RELAYCLIENT+1}" -o `id -u` != 64011 ];
then cat -;
else /usr/bin/spamc -x -U /var/run/spamd/spamd.sock;
fi) | /usr/sbin/qmail-queue.orig

For the records.

Tuesday, September 11, 2007

Introducing libcurls multi socket API

So, finally a first beta of pecl_http 1.6 has been released.


This is the first version which supports libcurls multi socket API introduced in 7.16 through libevent.


Here's a not very impressive comparison of the performance of the traditional multi API vs. the new multi socket API:



mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html

> 1.134667s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html

> 1.151088s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html

> 1.131867s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html -e

> 0.993878s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html -e

> 0.998832s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/empty.html -e

> 0.997121s

Above empty.html is, well, empty. The following test requests a 100k file:



mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin

> 2.205190s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin

> 2.210525s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin

> 2.254281s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin -e

> 2.007220s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin -e

> 1.945564s

mike@honeybadger:~/build/php-5.2-debug$ cli
~/cvs/pecl/http/scripts/bench_select_vs_event.php
-u http://honeybadger/100k.bin -e

> 1.969575s

So, apparently time savings are not huge, but noticable.

Wednesday, May 23, 2007

Silence

It's been more than 3 months that I brought back to mind, what was happening in my PHP/HTTP/CURL world, so here we go.


February:


pecl/http with support for persistent handles has been released.


A proposal of mine at internals to change the behaviour of read_property/write_property and get_property_ptr_ptr object handlers has successfully been ignored.


The idea was the following:




Wouldn't it be reasonable for the engine to use get_property_ptr_ptr() whenever it wants to modify a property and get rid of using read_property() for write access?


That would make rather simple ops like concatenation, in-/decrementation etc work again with overloaded internal classes. Just make the engine use read_property() followed by a write_property() when there's no get_property_ptr_ptr().




Nobody was interested.


March:


I added a comparison object handler to the DateTime class, which means that comparisons of DateTime objects should work in recent PHP5 versions.


I started development of pecl/libetpan, but dropped it again because of pretty huge differences between how the library works and how PHP is supposed to work. What a pity.


A less fine guy, some Omid, wanted me to write a PHP extension which calculates the strength of "poker hands", but he jumped off when I had done the algos.


April:


A fine guy, pretending his name was Andreas Weber, noticed that pecl/http's request method implementation was completely b0rked. Thanks to his report it was fixed in 1.5.3.


All fame Lukas Smith, queried me about what might have changed with my new output layer implementation for PHP6, but I noticed too late that it's been for a conference talk he was preparing, so I feel like I didn't spend enough attention to his questions. Sorry Lukas.


I started to implement libcurl's new multi_socket AKA hiper API in conjunction with libevent, but stumbled across a few problems.


May:


My journey with libcurl's multi_socket API continues, which eventually causes the delay of a first pecl/http 1.6 release candidate.


I tried Drupal for the first time.




Well, that'd be it. If it reads like an extrusion of junk, it probably was. ;)

Wednesday, May 9, 2007

Phar vs World

Recent discussions about inclusion of pecl/phar into the core distribution shows again that we are missing a defined process of handling additions to the PHP main distibution. How many people are really reading through all mails of 100+ message threads?


It's going to be a chaos. Always. Once a developer has got his new, shiny and soon-to-be-world-dominating extension into the core, he'll be a even stronger advocator of the "no-new-extensions" camp. Not to disrespect any work, but this is pure rivalism, masculine--really!


The idea of moving extensions from core to pecl is honorous, but we all know the current problems of this ideology.


Many people have asked me when pecl/http will be included in the main distribution. My answer is short and simple: "Never" (I usually add a tiny sentence, but that's nothing encouraging either).


Ah... and please do me a favour: rather keep your comments to yourself :) (...or toss it into the nonsense thread@internals).

Thursday, May 3, 2007

Two pitfalls in one afternoon

This is not my day.


<quote url="http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html">
words that are present in more than 50% of the rows are considered common and do not match
</quote>


RTFM! ;)

Apache MultiViews are evil

Suppose you've got a similar setup to:



RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [QSA,L]

RewriteRule ^network/?(w+)?$ network.php?path=$1

Apache will expand e.g. "network/foo/bar" to "network.php/foo/bar" which won't be expanded to "network.php?f=" because it --of course-- exists (RewriteCond -f).


Evil! :)