reduce cost of parsing http start line
authorMichael Wallner <mike@php.net>
Fri, 6 Feb 2015 11:13:19 +0000 (12:13 +0100)
committerMichael Wallner <mike@php.net>
Fri, 6 Feb 2015 11:13:19 +0000 (12:13 +0100)
php_http_info.c
php_http_version.c

index 876c720..9050919 100644 (file)
@@ -90,13 +90,22 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head
 
        /* is response */
        if (pre_header == http) {
-               char *status = NULL;
-               const char *code = http + sizeof("HTTP/X.x");
+               const char *status = NULL, *code = http + sizeof("HTTP/X.x");
                
                info->type = PHP_HTTP_RESPONSE;
                while (' ' == *code) ++code;
                if (code && end > code) {
-                       PHP_HTTP_INFO(info).response.code = strtol(code, &status, 10);
+                       /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */
+                       PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0');
+                       PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0');
+                       PHP_HTTP_INFO(info).response.code +=     *code++ - '0';
+                       if (PHP_HTTP_INFO(info).response.code < 100 || PHP_HTTP_INFO(info).response.code > 599) {
+                               if (free_info) {
+                                       php_http_info_free(&info);
+                               }
+                               return NULL;
+                       }
+                       status = code;
                } else {
                        PHP_HTTP_INFO(info).response.code = 0;
                }
index f4fcfc8..7adef9d 100644 (file)
@@ -27,7 +27,7 @@ php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major,
 php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str TSRMLS_DC)
 {
        long major, minor;
-       char separator = 0, *stop = NULL;
+       char separator = 0;
        register const char *ptr = str;
 
        switch (*ptr) {
@@ -40,16 +40,16 @@ php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *st
                ++ptr;
                /* no break */
        default:
-               major = strtol(ptr, &stop, 10);
-               if (stop && stop != ptr && major != LONG_MIN && major != LONG_MAX) {
-                       separator = *stop;
+               /* rfc7230#2.6 The HTTP version number consists of two decimal digits separated by a "." (period or decimal point) */
+               major = *ptr++ - '0';
+               if (major >= 0 && major <= 9) {
+                       separator = *ptr++;
                        if (separator) {
                                if (separator != '.' && separator != ',') {
-                                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr);
+                                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2);
                                }
-                               ptr = stop + 1;
-                               minor = strtol(ptr, &stop, 10);
-                               if (minor != LONG_MIN && minor != LONG_MAX) {
+                               minor = *ptr - '0';
+                               if (minor >= 0 && minor <= 9) {
                                        return php_http_version_init(v, major, minor TSRMLS_CC);
                                }
                        }