diff --git a/CMakeLists.txt b/CMakeLists.txt index 057ff9672..e3060e81b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,12 @@ cmake_minimum_required(VERSION 2.8) Project(openlitespeed) INCLUDE( ${PROJECT_SOURCE_DIR}/CMakeModules/common.cmake) +set(openlitespeed_MAJOR_VERSION 1) +set(openlitespeed_MINOR_VERSION 1) +set(openlitespeed_PATCH_VERSION 0) +set(openlitespeed_VERSION + ${FOOBAR_MAJOR_VERSION}.${FOOBAR_MINOR_VERSION}.${FOOBAR_PATCH_VERSION}) + SET(CMAKE_INCLUDE_CURRENT_DIR ON) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) diff --git a/CMakeModules/common.cmake b/CMakeModules/common.cmake index c9e475140..6a076009f 100644 --- a/CMakeModules/common.cmake +++ b/CMakeModules/common.cmake @@ -1,3 +1,3 @@ cmake_minimum_required(VERSION 2.8) -include_directories ("${PROJECT_SOURCE_DIR}/src") +include_directories ("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/src") diff --git a/configure b/configure index 5c9b9bee1..6f365b2d7 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for openlitespeed 1.03. +# Generated by GNU Autoconf 2.69 for openlitespeed 1.2. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='openlitespeed' PACKAGE_TARNAME='openlitespeed' -PACKAGE_VERSION='1.03' -PACKAGE_STRING='openlitespeed 1.03' +PACKAGE_VERSION='1.2' +PACKAGE_STRING='openlitespeed 1.2' PACKAGE_BUGREPORT='info@litespeedtech.com' PACKAGE_URL='http://www.litespeedtech.com/' @@ -743,6 +743,7 @@ with_admin with_password with_email enable_adminssl +enable_spdy enable_debug enable_rpath with_libdir @@ -1305,7 +1306,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures openlitespeed 1.03 to adapt to many kinds of systems. +\`configure' configures openlitespeed 1.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1371,7 +1372,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of openlitespeed 1.03:";; + short | recursive ) echo "Configuration of openlitespeed 1.2:";; esac cat <<\_ACEOF @@ -1385,8 +1386,9 @@ Optional Features: speeds up one-time build --disable-assert turn off assertions --enable-adminssl=[yes/no] - Enable SSL when logging to admin interface (modify - adminssl.conf before installation) [default=yes] + Enable HTTPS for admin console (modify adminssl.conf + before installation) [default=yes] + --enable-spdy Enable SPDY over HTTPS (Spdy is disabled by default) --enable-debug Enable debugging symbols (Debug is disabled by default) --disable-rpath Disable rpath (It is 'no' by default) @@ -1490,7 +1492,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -openlitespeed configure 1.03 +openlitespeed configure 1.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2127,7 +2129,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by openlitespeed $as_me 1.03, which was +It was created by openlitespeed $as_me 1.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2954,7 +2956,7 @@ fi # Define the identity of the package. PACKAGE='openlitespeed' - VERSION='1.03' + VERSION='1.2' # Some tools Automake needs. @@ -5128,6 +5130,15 @@ fi +# Check whether --enable-spdy was given. +if test "${enable_spdy+set}" = set; then : + enableval=$enable_spdy; +$as_echo "#define LS_ENABLE_SPDY 1" >>confdefs.h + + echo "SPDY enabled!!!" +fi + + # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; OPENLSWS_DEBUG="$enableval" @@ -5142,7 +5153,8 @@ if test "${enable_debug+set}" = set; then : fi - +CFLAGS="$CFLAGS -fstack-protector" +CXXFLAGS="$CXXFLAGS -fstack-protector" # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : @@ -5161,10 +5173,15 @@ if test "${with_libdir+set}" = set; then : else OSTYPE=`uname -m` - if test "$OSTYPE" != x86_64 ; then + OSNAME=`uname -s` + if test "$OSNAME" != Linux ; then OPENLSWS_LIBDIR=lib else - OPENLSWS_LIBDIR=lib64 + if test "$OSTYPE" != x86_64 ; then + OPENLSWS_LIBDIR=lib + else + OPENLSWS_LIBDIR=lib64 + fi fi fi @@ -7062,7 +7079,7 @@ fi done -ac_config_files="$ac_config_files Makefile src/Makefile src/edio/Makefile src/extensions/Makefile src/http/Makefile src/log4cxx/Makefile src/main/Makefile src/socket/Makefile src/sslpp/Makefile src/ssi/Makefile src/util/Makefile" +ac_config_files="$ac_config_files Makefile src/Makefile src/edio/Makefile src/extensions/Makefile src/http/Makefile src/spdy/Makefile src/log4cxx/Makefile src/main/Makefile src/socket/Makefile src/sslpp/Makefile src/ssi/Makefile src/util/Makefile" cat >confcache <<\_ACEOF @@ -7599,7 +7616,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by openlitespeed $as_me 1.03, which was +This file was extended by openlitespeed $as_me 1.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7666,7 +7683,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -openlitespeed config.status 1.03 +openlitespeed config.status 1.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -7802,6 +7819,7 @@ do "src/edio/Makefile") CONFIG_FILES="$CONFIG_FILES src/edio/Makefile" ;; "src/extensions/Makefile") CONFIG_FILES="$CONFIG_FILES src/extensions/Makefile" ;; "src/http/Makefile") CONFIG_FILES="$CONFIG_FILES src/http/Makefile" ;; + "src/spdy/Makefile") CONFIG_FILES="$CONFIG_FILES src/spdy/Makefile" ;; "src/log4cxx/Makefile") CONFIG_FILES="$CONFIG_FILES src/log4cxx/Makefile" ;; "src/main/Makefile") CONFIG_FILES="$CONFIG_FILES src/main/Makefile" ;; "src/socket/Makefile") CONFIG_FILES="$CONFIG_FILES src/socket/Makefile" ;; diff --git a/configure.in b/configure.in index 68bee6001..696bec0e1 100644 --- a/configure.in +++ b/configure.in @@ -5,8 +5,8 @@ m4_include(ax_lib_expat.m4) dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([openlitespeed],[1.03],[info@litespeedtech.com],[openlitespeed],[http://www.litespeedtech.com/]) -AM_INIT_AUTOMAKE([1.03 foreign no-define ]) +AC_INIT([openlitespeed],[1.2],[info@litespeedtech.com],[openlitespeed],[http://www.litespeedtech.com/]) +AM_INIT_AUTOMAKE([1.2 foreign no-define ]) AM_CONFIG_HEADER(src/config.h:src/config.h.in) @@ -75,10 +75,16 @@ AC_SUBST([OPENLSWS_EMAIL]) AC_ARG_ENABLE([adminssl], [AC_HELP_STRING([--enable-adminssl=@<:@yes/no@:>@], - [Enable SSL when logging to admin interface (modify adminssl.conf before installation) @<:@default=yes@:>@])], + [Enable HTTPS for admin console (modify adminssl.conf before installation) @<:@default=yes@:>@])], [OPENLSWS_ADMINSSL="$enableval"], [OPENLSWS_ADMINSSL=yes]) AC_SUBST([OPENLSWS_ADMINSSL]) +AC_ARG_ENABLE([spdy], + [AC_HELP_STRING([--enable-spdy], + [Enable SPDY over HTTPS (Spdy is disabled by default)])], + [ AC_DEFINE([LS_ENABLE_SPDY], [1], [Define if need spdy feature]) + echo "SPDY enabled!!!" ], []) + AC_ARG_ENABLE([debug], [AC_HELP_STRING([--enable-debug], [Enable debugging symbols (Debug is disabled by default)])], @@ -92,7 +98,8 @@ AC_ARG_ENABLE([debug], fi echo "OPENLSWS_DEBUG='$OPENLSWS_DEBUG' CFLAGS='$CFLAGS'" ], []) - +CFLAGS="$CFLAGS -fstack-protector" +CXXFLAGS="$CXXFLAGS -fstack-protector" AC_ARG_ENABLE([rpath], [AC_HELP_STRING([--disable-rpath], @@ -105,10 +112,15 @@ AC_ARG_WITH([libdir], AS_HELP_STRING([--with-libdir],[Set system lib directory. It is lib or lib64 and will be automatically checked by default]), [OPENLSWS_LIBDIR="$withval"], [ OSTYPE=`uname -m` - if test "$OSTYPE" != x86_64 ; then + OSNAME=`uname -s` + if test "$OSNAME" != Linux ; then OPENLSWS_LIBDIR=lib else - OPENLSWS_LIBDIR=lib64 + if test "$OSTYPE" != x86_64 ; then + OPENLSWS_LIBDIR=lib + else + OPENLSWS_LIBDIR=lib64 + fi fi ]) echo "Default system lib directory = $OPENLSWS_LIBDIR" @@ -155,6 +167,7 @@ AC_CONFIG_FILES(Makefile src/edio/Makefile src/extensions/Makefile src/http/Makefile + src/spdy/Makefile src/log4cxx/Makefile src/main/Makefile src/socket/Makefile diff --git a/dist/DEFAULT/html/index.html b/dist/DEFAULT/html/index.html index 2fe389a5b..8e1322b9c 100644 --- a/dist/DEFAULT/html/index.html +++ b/dist/DEFAULT/html/index.html @@ -40,12 +40,11 @@

Congratulation! You have successfully
-powered 
-by
-Faster, Easier and Safer!

- - Copyright © 2003. Lite Speed +powered 
+by
+

+ + Copyright © 2013. Lite Speed Technologies Inc.
All rights reserved.
diff --git a/dist/DEFAULT/html/powered_by.gif b/dist/DEFAULT/html/powered_by.gif deleted file mode 100644 index dcc6ea699..000000000 Binary files a/dist/DEFAULT/html/powered_by.gif and /dev/null differ diff --git a/dist/DEFAULT/html/poweredby_openlitespeed.png b/dist/DEFAULT/html/poweredby_openlitespeed.png new file mode 100644 index 000000000..228763c28 Binary files /dev/null and b/dist/DEFAULT/html/poweredby_openlitespeed.png differ diff --git a/dist/VERSION b/dist/VERSION index ee90284c2..6085e9465 100644 --- a/dist/VERSION +++ b/dist/VERSION @@ -1 +1 @@ -1.0.4 +1.2.1 diff --git a/dist/admin/html.open/classes/CValidation.php b/dist/admin/html.open/classes/CValidation.php new file mode 100644 index 000000000..dbec5e12e --- /dev/null +++ b/dist/admin/html.open/classes/CValidation.php @@ -0,0 +1,939 @@ +_info = NULL; + } + + public function ExtractPost($tbl, &$d, $disp) + { + $this->_info = $disp->_info; + $goFlag = 1 ; + $index = array_keys($tbl->_dattrs); + foreach ( $index as $i ) { + $attr = $tbl->_dattrs[$i]; + + if ( $attr == NULL || $attr->bypassSavePost()) + continue; + + $d[$attr->_key] = $attr->extractPost(); + $needCheck = TRUE; + if ( $attr->_type == 'sel1' || $attr->_type == 'sel2' ) { + if ( $disp->_act == 'c' ) { + $needCheck = FALSE; + } + else { + $attr->populate_sel1_options($this->_info, $d); + } + } + + if ( $needCheck ) { + $res = $this->validateAttr($attr, $d[$attr->_key]); + $this->setValid($goFlag, $res); + } + } + + $res = $this->validatePostTbl($tbl, $d); + $this->setValid($goFlag, $res); + + $this->_info = NULL; + + // if 0 , make it always point to curr page + return $goFlag; + } + + protected function checkListener(&$listener) + { + if ( $listener['secure']->GetVal() == '0' ) { + if ( isset($listener['certFile']) && !$listener['certFile']->HasVal() ) { + $listener['certFile']->SetErr(NULL); + } + if ( isset($listener['keyFile']) && !$listener['keyFile']->HasVal() ) { + $listener['keyFile']->SetErr(NULL); + } + } else { + $tids = array('L_SSL_CERT'); + $this->validateElement($tids, $listener); + } + } + + protected function validateElement($tids, &$data) + { + $tblDef = DTblDef::GetInstance(); + $valid = 1; + foreach ( $tids as $tid ) { + $tbl = $tblDef->GetTblDef($tid); + $d = &DUtil::locateData( $data, $tbl->_dataLoc ); + + if ( $d == NULL ) continue; + + if ( $tbl->_holderIndex != NULL ) { + $keys = array_keys( $d ); + foreach( $keys as $key ) { + $res = $this->validateTblAttr($tblDef, $tbl, $d[$key]); + $this->setValid($valid, $res); + } + } else { + $res = $this->validateTblAttr($tblDef, $tbl, $d); + $this->setValid($valid, $res); + } + } + return $valid; + } + + protected function setValid(&$valid, $res) + { + if ( $valid != -1 ) { + if ( $res == -1 ) { + $valid = -1; + } elseif ( $res == 0 && $valid == 1 ) { + $valid = 0; + } + } + if ( $res == 2 ) { + $valid = 2; + } + } + + protected function validatePostTbl($tbl, &$d) + { + $isValid = 1; + if ( $tbl->_holderIndex != NULL && isset($d[$tbl->_holderIndex])) { + $newref = $d[$tbl->_holderIndex]->GetVal(); + $oldref = NULL; + + if(isset($this->_info['holderIndex_cur'])) { + $oldref = $this->_info['holderIndex_cur']; + } + //echo "oldref = $oldref newref = $newref \n"; + if ( $oldref == NULL || $newref != $oldref ) { + if (isset($this->_info['holderIndex']) && $this->_info['holderIndex'] != NULL + && in_array($newref, $this->_info['holderIndex']) ) { + $d[$tbl->_holderIndex]->SetErr('This value has been used! Please choose a unique one.'); + $isValid = -1; + } + } + } + + $checkedTids = array('VH_TOP_D','VH_BASE','VH_UDB', 'ADMIN_USR', 'ADMIN_USR_NEW', + 'L_GENERAL', 'L_GENERAL1', 'ADMIN_L_GENERAL', 'ADMIN_L_GENERAL1', 'L_SSL', 'L_CERT', 'L_SSL_CERT', + 'TP', 'TP1'); + + if ( in_array($tbl->_id, $checkedTids) ) { + switch ($tbl->_id) { + case 'TP': + case 'TP1': + $isValid = $this->chkPostTbl_TP($d); + break; + case 'VH_BASE': + case 'VH_TOP_D': + $isValid = $this->chkPostTbl_VH_BASE($d); + break; + case 'VH_UDB': + $isValid = $this->chkPostTbl_VH_UDB($d); + break; + case 'ADMIN_USR': + $isValid = $this->chkPostTbl_ADMIN_USR($d); + break; + case 'ADMIN_USR_NEW': + $isValid = $this->chkPostTbl_ADMIN_USR_NEW($d); + break; + case 'L_GENERAL': + case 'L_GENERAL1': + case 'ADMIN_L_GENERAL': + case 'ADMIN_L_GENERAL1': + $isValid = $this->chkPostTbl_L_GENERAL($d); + break; + case 'L_SSL': + $isValid = $this->chkPostTbl_L_SSL($d); + break; + case 'L_CERT': + case 'L_SSL_CERT': + $isValid = $this->chkPostTbl_L_SSL_CERT($d); + break; + } + } + + return $isValid; + } + + + protected function chkPostTbl_TP(&$d) + { + $isValid = 1; + + $confCenter = ConfCenter::singleton(); + + $oldName = trim($confCenter->GetDispInfo()->_name); + $newName = trim($d['name']->GetVal()); + + if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['tpTop'])) { + $d['name']->SetErr("Template: \"$newName\" already exists. Please use a different name."); + $isValid = -1; + + } + + return $isValid; + } + + protected function chkPostTbl_VH_BASE(&$d) + { + $isValid = 1; + + $confCenter = ConfCenter::singleton(); + + $oldName = trim($confCenter->GetDispInfo()->_name); + $newName = trim($d['name']->GetVal()); + + if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['vhTop'])) { + $d['name']->SetErr("Virtual Hostname: \"$newName\" already exists. Please use a different name."); + $isValid = -1; + + } + + return $isValid; + } + + protected function chkPostTbl_VH_UDB(&$d) + { + $isValid = 1; + if ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) { + $d['pass']->SetErr('Passwords do not match!'); + $isValid = -1; + } + + if ( !$d['pass']->HasVal() ) { //new user + $d['pass']->SetErr('Missing password!'); + $isValid = -1; + } + + if ( $isValid == -1 ) { + return -1; + } + + if ( strlen($d['pass']->GetVal()) > 0 ) { + $newpass = $this->encryptPass($d['pass']->GetVal()); + $d['passwd'] = new CVal($newpass); + } + return 1; + } + + protected function encryptPass($val) + { + $valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."; + if (CRYPT_MD5 == 1) + { + $salt = '$1$'; + for($i = 0; $i < 8; $i++) + { + $salt .= $valid_chars[rand(0,strlen($valid_chars)-1)]; + } + $salt .= '$'; + } + else + { + $salt = $valid_chars[rand(0,strlen($valid_chars)-1)]; + $salt .= $valid_chars[rand(0,strlen($valid_chars)-1)]; + } + $pass = crypt($val, $salt); + return $pass; + } + + protected function chkPostTbl_ADMIN_USR(&$d) + { + $isValid = 1; + if ( !$d['oldpass']->HasVal() ) { + $d['oldpass']->SetErr('Missing Old password!'); + $isValid = -1; + } else { + $file = $_SERVER['LS_SERVER_ROOT'] . 'admin/conf/htpasswd'; + $udb = ConfigFileEx::loadUserDB($file); + $olduser = $this->_info['holderIndex_cur']; + $passwd = $udb[$olduser]['passwd']->GetVal(); + + $oldpass = $d['oldpass']->GetVal(); + $encypt = crypt($oldpass, $passwd); + + if ( $encypt != $passwd ) { + $d['oldpass']->SetErr('Invalid old password!'); + $isValid = -1; + } + } + + if ( !$d['pass']->HasVal() ) { + $d['pass']->SetErr('Missing new password!'); + $isValid = -1; + } elseif ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) { + $d['pass']->SetErr('New passwords do not match!'); + $isValid = -1; + } + + if ( $isValid == -1 ) { + return -1; + } + + $newpass = $this->encryptPass($d['pass']->GetVal()); + $d['passwd'] = new CVal($newpass); + + return 1; + } + + protected function chkPostTbl_ADMIN_USR_NEW(&$d) + { + $isValid = 1; + if ( !$d['pass']->HasVal() ) { + $d['pass']->SetErr('Missing new password!'); + $isValid = -1; + } elseif ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) { + $d['pass']->SetErr('New passwords do not match!'); + $isValid = -1; + } + + if ( $isValid == -1 ) { + return -1; + } + + $newpass = $this->encryptPass($d['pass']->GetVal()); + $d['passwd'] = new CVal($newpass); + + return 1; + } + + protected function chkPostTbl_L_GENERAL(&$d) + { + $isValid = 1; + + $ip = $d['ip']->GetVal(); + if ( $ip == 'ANY' ) { + $ip = '*'; + } + $port = $d['port']->GetVal(); + $d['address'] = new CVal("$ip:$port"); + + $confCenter = ConfCenter::singleton(); + + $oldName = trim($confCenter->GetDispInfo()->_name); + $newName = trim($d['name']->GetVal()); + + if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['listeners'])) { + $d['name']->SetErr("Listener \"$newName\" already exists. Please use a different name."); + $isValid = -1; + } + + return $isValid; + } + + protected function isCurrentListenerSecure() + { + $confCenter = ConfCenter::singleton(); + $listenerName = trim($confCenter->GetDispInfo()->_name); + $l = $confCenter->_serv->_data['listeners'][$listenerName]; + return ($l['secure']->GetVal() == 1); + } + + protected function chkPostTbl_L_SSL(&$d) + { + $isValid = 1; + if ($this->isCurrentListenerSecure()) { + $err = 'Value must be set for secured listener'; + if (!$d['sslProtocol']->HasVal()) { + $d['sslProtocol']->SetErr($err); + $isValid = -1; + } + if (!$d['ciphers']->HasVal()) { + $d['ciphers']->SetErr($err); + $isValid = -1; + } + } + + return $isValid; + } + + protected function chkPostTbl_L_SSL_CERT(&$d) + { + $isValid = 1; + if ($this->isCurrentListenerSecure()) { + $err = 'Value must be set for secured listener'; + if (!$d['keyFile']->HasVal()) { + $d['keyFile']->SetErr($err); + $isValid = -1; + } + if (!$d['certFile']->HasVal()) { + $d['certFile']->SetErr($err); + $isValid = -1; + } + } + + return $isValid; + } + + protected function validateTblAttr($tblDef, $tbl, &$data) + { + $valid = 1; + if ( $tbl->_subTbls != NULL ) { + $tid = DUtil::getSubTid($tbl->_subTbls, $data); + if ( $tid == NULL ) { + return; + } + $tbl1 = $tblDef->GetTblDef($tid); + } else { + $tbl1 = $tbl; + } + + $index = array_keys($tbl1->_dattrs); + foreach ( $index as $i ) { + $attr = $tbl1->_dattrs[$i]; + + if ( $attr->_type == 'sel1' || $attr->_type == 'sel2' ) { + $attr->populate_sel1_options($this->_info, $data); + } + + $res = $this->validateAttr($attr, $data[$attr->_key]); + $this->setValid($valid, $res); + } + return $valid; + } + + protected function validateAttr($attr, &$cvals) + { + $valid = 1; + if ( is_array($cvals) ) { + for ( $i = 0 ; $i < count($cvals) ; ++$i ) { + $res = $this->isValidAttr($attr, $cvals[$i]); + $this->setValid($valid, $res); + } + } else { + $valid = $this->isValidAttr($attr, $cvals); + } + return $valid; + } + + protected function isValidAttr($attr, $cval) + { + if ($cval == NULL || $cval->HasErr()) + return -1; + + if ( !$cval->HasVal()) { + if ( $attr->_allowNull ) { + return 1; + } + $cval->SetErr('value must be set'); + return -1; + } + + if ( $attr->_type == 'cust' ) { + return 1; + } + + $chktype = array('uint', 'name', 'vhname', 'sel','sel1','sel2', + 'bool','file','filep','file0','file1', 'filetp', 'path', + 'uri','expuri','url', 'httpurl', 'email', 'dir', 'addr', 'parse'); + + if ( !in_array($attr->_type, $chktype) ) { + // not checked type ('domain', 'subnet' + return 1; + } + + $type3 = substr($attr->_type, 0, 3); + if ( $type3 == 'sel' ) { + // for sel, sel1, sel2 + $funcname = 'chkAttr_sel'; + } + elseif ( $type3 == 'fil' || $type3 == 'pat' ) { + $funcname = 'chkAttr_file'; + } + else { + $funcname = 'chkAttr_' . $attr->_type; + } + + if ( $attr->_multiInd == 1 ) { + $valid = 1; + $vals = DUtil::splitMultiple($cval->GetVal()); + $err = array(); + $funcname .= '_val'; + foreach( $vals as $i=>$v ) { + $res = $this->$funcname($attr, $v, $err[$i]); + $this->setValid($valid, $res); + } + $cval->SetErr(trim(implode(' ', $err))); + return $valid; + }else { + return $this->$funcname($attr, $cval); + } + } + + protected function chkAttr_sel($attr, $cval) + { + $err = ''; + $res = $this->chkAttr_sel_val($attr, $cval->GetVal(), $err); + $cval->SetErr($err); + return $res; + } + + protected function chkAttr_sel_val($attr, $val, &$err) + { + if ( isset( $attr->_maxVal ) + && !array_key_exists($val, $attr->_maxVal) ) { + $err = "invalid value: $val"; + return -1; + } + return 1; + } + + protected function chkAttr_name($attr, $cval) + { + $cval->SetVal( preg_replace("/\s+/", ' ', $cval->GetVal())); + $res = $this->chkAttr_name_val($attr, $cval->GetVal(), $err); + $cval->SetErr($err); + return $res; + } + + protected function chkAttr_name_val($attr, $val, &$err) + { + if ( preg_match( "/[<>&%]/", $val) ) { + $err = 'invalid characters in name'; + return -1; + } + if ( strlen($val) > 100 ) { + $err = 'name can not be longer than 100 characters'; + return -1; + } + return 1; + } + + protected function chkAttr_vhname($attr, $cval) + { + $cval->SetVal(preg_replace("/\s+/", ' ', $cval->GetVal())); + $val = $cval->GetVal(); + if ( preg_match( "/[,;<>&%]/", $val ) ) { + $cval->SetErr('Invalid characters found in name'); + return -1; + } + if ( strpos($val, ' ') !== FALSE ) { + $cval->SetErr('No space allowed in the name'); + return -1; + } + if ( strlen($val) > 100 ) { + $cval->SetErr('name can not be longer than 100 characters'); + return -1; + } + $this->_info['VH_NAME'] = $val; + return 1; + } + + protected function allow_create($attr, $absname) + { + if ( strpos($attr->_maxVal, 'c') === FALSE ) { + return FALSE; + } + if ( $attr->_minVal >= 2 + && ( strpos($absname, $_SERVER['LS_SERVER_ROOT']) === 0 )) { + return TRUE; + } + + if (isset($this->_info['VH_ROOT'])) { + $VH_ROOT = $this->_info['VH_ROOT']; + } else { + $VH_ROOT = NULL; + } + + if (isset($this->_info['DOC_ROOT'])) { + $DOC_ROOT = $this->_info['DOC_ROOT']; + } + + if ( $attr->_minVal >= 3 && ( strpos($absname, $VH_ROOT) === 0 ) ) { + return TRUE; + } + + if ( $attr->_minVal == 4 && ( strpos($absname, $DOC_ROOT) === 0 ) ) { + return TRUE; + } + + return FALSE; + } + + protected function test_file(&$absname, &$err, $attr) + { + $absname = PathTool::clean($absname); + if ( isset( $_SERVER['LS_CHROOT'] ) ) { + $root = $_SERVER['LS_CHROOT']; + $len = strlen($root); + if ( strncmp( $absname, $root, $len ) == 0 ) { + $absname = substr($absname, $len); + } + } + + if ( $attr->_type == 'file0' ) { + if ( !file_exists($absname) ) { + return 1; //allow non-exist + } + } + if ( $attr->_type == 'path' || $attr->_type == 'filep' || $attr->_type == 'dir' ) { + $type = 'path'; + } else { + $type = 'file'; + } + + if ( ($type == 'path' && !is_dir($absname)) + || ($type == 'file' && !is_file($absname)) ) { + $err = $type .' '. htmlspecialchars($absname) . ' does not exist.'; + if ( $this->allow_create($attr, $absname) ) { + $err .= ' CLICK TO CREATE'; + } else { + $err .= ' Please create manually.'; + } + + return -1; + } + if ( (strpos($attr->_maxVal, 'r') !== FALSE) && !is_readable($absname) ) { + $err = $type . ' '. htmlspecialchars($absname) . ' is not readable'; + return -1; + } + if ( (strpos($attr->_maxVal, 'w') !== FALSE) && !is_writable($absname) ) { + $err = $type . ' '. htmlspecialchars($absname) . ' is not writable'; + return -1; + } + if ( (strpos($attr->_maxVal, 'x') !== FALSE) && !is_executable($absname) ) { + $err = $type . ' '. htmlspecialchars($absname) . ' is not executable'; + return -1; + } + return 1; + } + + protected function chkAttr_file($attr, $cval) + { + $val = $cval->GetVal(); + $err = ''; + $res = $this->chkAttr_file_val($attr, $val, $err); + $cval->SetVal($val); + $cval->SetErr($err); + return $res; + } + + protected function chkAttr_dir($attr, $cval) + { + $val = $cval->GetVal(); + $err = ''; + + if ( substr($val,-1) == '*' ) { + $res = $this->chkAttr_file_val($attr, substr($val,0,-1), $err); + } else { + $res = $this->chkAttr_file_val($attr, $val, $err); + } + $cval->SetVal($val); + $cval->SetErr($err); + return $res; + } + + public function chkAttr_file_val($attr, $val, &$err) + { + //this is public + clearstatcache(); + $err = NULL; + + if ( $attr->_type == 'filep' ) { + $path = substr($val, 0, strrpos($val,'/')); + } else { + $path = $val; + if ( $attr->_type == 'file1' ) { + $pos = strpos($val, ' '); + if ( $pos > 0 ) { + $path = substr($val, 0, $pos); + } + } + } + + $res = $this->chk_file1($attr, $path, $err); + if ($attr->_type == 'filetp') { + $pathtp = $_SERVER['LS_SERVER_ROOT'] . 'conf/templates/'; + if (strstr($path, $pathtp) === FALSE) { + $err = ' Template file must locate within $SERVER_ROOT/conf/templates/'; + $res = -1; + } + else if (substr($path, -4) != '.xml') { + $err = ' Template file name needs to be ".xml"'; + $res = -1; + } + } + if ( $res == -1 + && $_POST['file_create'] == $attr->_htmlName + && $this->allow_create($attr, $path) ) { + if ( PathTool::createFile($path, $err, $attr->_htmlName) ) { + $err = "$path has been created successfully."; + } + $res = 0; // make it always point to curr page + } + if ( $attr->_key == 'vhRoot' ) { + if ( substr($path,-1) != '/' ) { + $path .= '/'; + } + if ($res == -1) { + // do not check path for vhroot, it may be different owner + $err = ''; + $res = 1; + } + $this->_info['VH_ROOT'] = $path; + } + elseif ($attr->_key == 'docRoot') { + if ($res == -1) { + // do not check path for vhroot, it may be different owner + $err = ''; + $res = 1; + } + } + return $res; + } + + protected function chk_file1($attr, &$path, &$err) + { + if(!strlen($path)) { + $err = "Invalid Path."; + return -1; + } + + $s = $path{0}; + + if ( strpos($path, '$VH_NAME') !== FALSE ) { + $path = str_replace('$VH_NAME', $this->_info['VH_NAME'], $path); + } + + if ( $s == '/' ) { + return $this->test_file($path, $err, $attr); + } + + if ( $attr->_minVal == 1 ) { + $err = 'only accept absolute path'; + return -1; + } + elseif ( $attr->_minVal == 2 ) { + if ( strncasecmp('$SERVER_ROOT', $path, 12) != 0 ) { + $err = 'only accept absolute path or path relative to $SERVER_ROOT' . $path; + return -1; + } else { + $path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13); + } + } + elseif ( $attr->_minVal == 3 ) { + if ( strncasecmp('$SERVER_ROOT', $path, 12) == 0 ) { + $path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13); + } elseif ( strncasecmp('$VH_ROOT', $path, 8) == 0 ) { + if (isset($this->_info['VH_ROOT'])) { + $path = $this->_info['VH_ROOT'] . substr($path, 9); + } + } else { + $err = 'only accept absolute path or path relative to $SERVER_ROOT or $VH_ROOT'; + return -1; + } + } + elseif ( $attr->_minVal == 4 ) { + if ( strncasecmp('$SERVER_ROOT', $path, 12) == 0 ) { + $path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13); + } elseif ( strncasecmp('$VH_ROOT', $path, 8) == 0 ) { + $path = $this->_info['VH_ROOT'] . substr($path, 9); + } elseif ( strncasecmp('$DOC_ROOT', $path, 9) == 0 ) { + $path = $this->_info['DOC_ROOT'] . substr($path, 10); + } else { + $path = $this->_info['DOC_ROOT'] . $path; + } + } + + return $this->test_file($path, $err, $attr); + } + + protected function chkAttr_uri($attr, $cval) + { + $val = $cval->GetVal(); + if ( $val[0] != '/' ) { + $cval->SetErr('URI must start with "/"'); + return -1; + } + return 1; + } + + protected function chkAttr_expuri($attr, $cval) + { + $val = $cval->GetVal(); + if ( $val{0} == '/' || strncmp( $val, 'exp:', 4 ) == 0 ) { + return 1; + } else { + $cval->SetErr('URI must start with "/" or "exp:"'); + return -1; + } + } + + protected function chkAttr_url($attr, $cval) + { + $val = $cval->GetVal(); + if (( $val{0} != '/' ) + &&( strncmp( $val, 'http://', 7 ) != 0 ) + &&( strncmp( $val, 'https://', 8 ) != 0 )) { + $cval->SetErr('URL must start with "/" or "http(s)://"'); + return -1; + } + return 1; + } + + protected function chkAttr_httpurl($attr, $cval) + { + $val = $cval->GetVal(); + if (strncmp( $val, 'http://', 7 ) != 0 ) { + $cval->SetErr('Http URL must start with "http://"'); + return -1; + } + return 1; + } + + protected function chkAttr_email($attr, $cval) + { + $err = ''; + $res = $this->chkAttr_email_val($attr, $cval->GetVal(), $err); + $cval->SetErr($err); + return $res; + } + + protected function chkAttr_email_val($attr, $val, &$err) + { + if ( preg_match("/^[[:alnum:]._-]+@.+/", $val ) ) { + return 1; + } else { + $err = 'invalid email format: ' . $val; + return -1; + } + } + + protected function chkAttr_addr($attr, $cval) + { + if ( preg_match("/^[[:alnum:]._-]+:(\d)+$/", $cval->GetVal()) ) { + return 1; + } elseif ( preg_match("/^UDS:\/\/.+/i", $cval->GetVal()) ) { + return 1; + } else { + $cval->SetErr('invalid address: correct syntax is "IPV4|IPV6_address:port" or UDS://path'); + return -1; + } + } + + protected function chkAttr_bool($attr, $cval) + { + $val = $cval->GetVal(); + if ( $val === '1' || $val === '0' ) { + return 1; + } + $cval->SetErr('invalid value'); + return -1; + } + + protected function chkAttr_parse($attr, $cval) + { + $err = ''; + $res = $this->chkAttr_parse_val($attr, $cval->GetVal(), $err); + $cval->SetErr($err); + return $res; + } + + protected function chkAttr_parse_val($attr, $val, &$err) + { + if ( preg_match($attr->_minVal, $val) ) { + return 1; + } else { + $err = "invalid format - $val, syntax is {$attr->_maxVal}"; + return -1; + } + } + + protected function getKNum($strNum) + { + $tag = substr($strNum, -1); + switch( $tag ) { + case 'K': + case 'k': $multi = 1024; break; + case 'M': + case 'm': $multi = 1048576; break; + case 'G': + case 'g': $multi = 1073741824; break; + default: return intval($strNum); + } + + return (intval(substr($strNum, 0, -1)) * $multi); + } + + protected function chkAttr_uint($attr, $cval) + { + $val = $cval->GetVal(); + if ( preg_match("/^(-?\d+)([KkMmGg]?)$/", $val, $m) ) { + $val1 = $this->getKNum($val); + if (isset($attr->_minVal)) { + $min = $this->getKNum($attr->_minVal); + if ($val1 < $min) { + $cval->SetErr('number is less than the minumum required'); + return -1; + } + + } + if (isset($attr->_maxVal)) { + $max = $this->getKNum($attr->_maxVal); + if ( $val1 > $max ) { + $cval->SetErr('number exceeds maximum allowed'); + return -1; + } + } + return 1; + } else { + $cval->SetErr('invalid number format'); + return -1; + } + } + + protected function chkDups(&$data, &$checkList, $key) + { + if ( in_array( $data[$key]->GetVal(), $checkList ) ) { + $data[$key]->SetErr( "This $key \"" . $data[$key]->GetVal() . '\" already exists. Please enter a different one.'); + return FALSE; + } + return TRUE; + } + + protected function chkExtApp(&$data, &$attr) + { + $isValid = TRUE; + if ( $data['autoStart']->GetVal() ) { + if ( !$data['path']->HasVal() ) { + $data['path']->SetErr('must provide path when autoStart is enabled'); + $isValid = FALSE; + } + if ( !$data['backlog']->HasVal() ) { + $data['backlog']->SetErr('must enter backlog value when autoStart is enabled'); + $isValid = FALSE; + } + if ( !$data['instances']->HasVal() ) { + $data['instances']->SetErr('must give number of instances when autoStart is enabled'); + $isValid = FALSE; + } + } + + if ( isset($attr['names']) && (!$this->chkDups($to, $attr['names'], 'name')) ) { + $isValid = FALSE; + } + return $isValid; + } + + protected function chkScriptHandler(&$to, &$attr) + { + $vals = DUtil::splitMultiple( $to['suffix']->GetVal() ); + $isValid = TRUE; + foreach( $vals as $suffix ) { + if ( in_array( $suffix, $attr['names'] ) ) { + $t[] = $suffix; + $isValid = FALSE; + } + } + if ( !$isValid ) { + $to['suffix']->SetErr(' Suffix ' . implode(', ', $t) . ' already exists. Please use a different suffix.'); + } + return $isValid; + } + +} diff --git a/dist/admin/html.open/classes/ConfValidation.php b/dist/admin/html.open/classes/ConfValidation.php index 451cfcf3e..24ddb3bf5 100644 --- a/dist/admin/html.open/classes/ConfValidation.php +++ b/dist/admin/html.open/classes/ConfValidation.php @@ -101,7 +101,7 @@ public function CheckListener(&$listener) $listener['keyFile']->SetErr(NULL); } } else { - $tids = array('L_CERT'); + $tids = array('L_SSL_CERT'); $this->validateElement($tids, $listener); } } @@ -396,41 +396,11 @@ private function chkPostTbl_ADMIN_L_GENERAL1(&$d) } private function chkPostTbl_L_SSL(&$d) - { - /* array( 'SSLv3' => ' ', 'TLSv1' => ' ', - 'HIGH' => ' ', 'MEDIUM' => ' ', 'LOW' => ' ', - 'EXPORT56' => ' ', 'EXPORT40' => ' ', 'eNULL' => ' ');*/ - $ciphers = ''; - - if (isset($_POST['ck1'])) { - $ciphers .= 'SSLv3:'; - } - if (isset($_POST['ck2'])) { - $ciphers .= 'TLSv1:'; - } - if (isset($_POST['ck3'])) { - $ciphers .= 'HIGH:'; - } - if (isset($_POST['ck4'])) { - $ciphers .= 'MEDIUM:'; - } - if (isset($_POST['ck5'])) { - $ciphers .= 'LOW:'; - } - if (isset($_POST['ck6'])) { - $ciphers .= 'EXPORT56:'; - } - if (isset($_POST['ck7'])) { - $ciphers .= 'EXPORT40:'; - } - if ($ciphers == '') { - $d['ciphers'] = new CVal('', 'Need to select at least one'); + { // validate inside attr + if ($d['ciphers']->HasErr()) return -1; - } - - $ciphers .= '!aNULL:!MD5:!SSLv2:!eNULL:!EDH'; - $d['ciphers'] = new CVal($ciphers); - return 1; + else + return 1; } private function chkPostTbl_VH_SSL_SSL(&$d) @@ -500,7 +470,7 @@ private function isValidAttr($attr, $cval) $chktype = array('uint', 'name', 'vhname', 'sel','sel1','sel2', 'bool','file','filep','file0','file1', 'filetp', 'path', - 'uri','expuri','url', 'email', 'dir', 'addr', 'parse'); + 'uri','expuri','url', 'httpurl', 'email', 'dir', 'addr', 'parse'); if ( !in_array($attr->_type, $chktype) ) { // not checked type ('domain', 'subnet' @@ -846,6 +816,16 @@ private function chkAttr_url($attr, $cval) return 1; } + private function chkAttr_httpurl($attr, $cval) + { + $val = $cval->GetVal(); + if (strncmp( $val, 'http://', 7 ) != 0 ) { + $cval->SetErr('Http URL must start with "http://"'); + return -1; + } + return 1; + } + private function chkAttr_email($attr, $cval) { $err = ''; @@ -871,7 +851,7 @@ private function chkAttr_addr($attr, $cval) } elseif ( preg_match("/^UDS:\/\/.+/i", $cval->GetVal()) ) { return 1; } else { - $cval->SetErr('invalid address: correct syntax is "IPV4_address:port" or UDS://path'); + $cval->SetErr('invalid address: correct syntax is "IPV4|IPV6_address:port" or UDS://path'); return -1; } } diff --git a/dist/admin/html.open/classes/DATTR_HELP_ITEM.php b/dist/admin/html.open/classes/DATTR_HELP_ITEM.php index f57e22b17..d573275df 100644 --- a/dist/admin/html.open/classes/DATTR_HELP_ITEM.php +++ b/dist/admin/html.open/classes/DATTR_HELP_ITEM.php @@ -12,7 +12,7 @@ function __construct($name, $desc, $tips = NULL, $syntax = NULL, $example = NULL $this->name = $name; $this->desc = $desc; - $this->tips = $tips; + $this->tips = str_replace('
', '
', $tips); $this->syntax = $syntax; $this->example = $example; } @@ -21,7 +21,7 @@ function __construct($name, $desc, $tips = NULL, $syntax = NULL, $example = NULL function render($key, $blocked_version=0) { $key = str_replace(array(':','_'), '', $key ); - $buf = '' + $buf = '' . '
' . $this->name . '' ; @@ -39,27 +39,22 @@ function render($key, $blocked_version=0) . $this->desc . '

'; if ($this->syntax) { - $buf .= 'Syntax: ' + $buf .= 'Syntax: ' . $this->syntax . '

'; } if ($this->example) { - $buf .= 'Example: ' + $buf .= 'Example: ' . $this->example . '

'; } if ($this->tips) { - $buf .= 'Tip(s):
    '; - if (strpos($this->tips, '
    ') !== FALSE) { - $tips = explode('
    ', $this->tips); - foreach($tips as $ti) { - $ti = trim($ti); - if ($ti != '') - $buf .= '
  • ' . $ti . '
  • '; - } - } - else { - $buf .= '
  • ' . $this->tips . '
  • '; + $buf .= 'Tip(s):
      '; + $tips = explode('
      ', $this->tips); + foreach($tips as $ti) { + $ti = trim($ti); + if ($ti != '') + $buf .= '
    • ' . $ti . '
    • '; } $buf .= '
    '; } diff --git a/dist/admin/html.open/classes/DAttrBase.php b/dist/admin/html.open/classes/DAttrBase.php new file mode 100644 index 000000000..790c7ea78 --- /dev/null +++ b/dist/admin/html.open/classes/DAttrBase.php @@ -0,0 +1,499 @@ +_htmlName = $key; + $this->_key = $key; + $this->_type = $type; + $this->_label = $label; + $this->_minVal = $min; + $this->_maxVal = $max; + $this->_inputType = $inputType; + $this->_inputAttr = $inputAttr; + $this->_allowNull = $allowNull; + $this->_multiInd = $multiInd; + $this->_helpKey = ($helpKey == NULL)? $key:$helpKey; + } + + public function dup($key, $label, $helpkey) + { + $cname = get_class($this); + $d = new $cname($this->_key, $this->_type, $this->_label, $this->_inputType, $this->_allowNull, + $this->_minVal, $this->_maxVal, $this->_inputAttr, $this->_multiInd, $this->_helpKey); + + $d->_htmlName = $this->_htmlName; + $d->_glue = $this->_glue; + $d->_href = $this->_href; + $d->_hrefLink = $this->_hrefLink; + $d->_FDE = $this->_FDE; + $d->_note = $this->_note; + $d->_icon = $this->_icon; + + + if ( $key != NULL ) + { + $d->_htmlName = $key; + $d->_key = $key; + } + if ($label != NULL) + $d->_label = $label; + + if ($helpkey != NULL) + $d->_helpKey = $helpkey; + + return $d; + } + + protected function extractCheckBoxOr() + { + $value = 0; + $novalue = 1; + foreach( $this->_maxVal as $val => $disp ) + { + $name = $this->_key . $val; + if ( isset( $_POST[$name] ) ) + { + $novalue = 0; + $value = $value | $val; + } + } + if ( $novalue ) { + if ($this->_minVal !== NULL) // has default value + return 0; + else + return ''; + } + else + return $value; + } + + + protected function extractSplitMultiple(&$value) + { + if ( $this->_glue == ' ' ) + $vals = preg_split("/[,; ]+/", $value, -1, PREG_SPLIT_NO_EMPTY); + else + $vals = preg_split("/[,;]+/", $value, -1, PREG_SPLIT_NO_EMPTY); + + $vals1 = array(); + foreach( $vals as $val ) + { + $val1 = trim($val); + if ( strlen($val1) > 0 && !in_array($val1,$vals1)) { + $vals1[] = $val1; + } + } + + if ( $this->_glue == ' ') + $value = implode(' ', $vals1); + else + $value = implode(', ', $vals1); + } + + protected function toHtmlContent($cval, $refUrl=NULL) + { + $o = ''; + if ( $cval == NULL || !$cval->HasVal()) { + $o .= 'Not Set'; + return $o; + } + + $value = $cval->GetVal(); + $err = $cval->GetErr(); + + if ( $this->_type == 'sel1' && $value != NULL && !array_key_exists($value, $this->_maxVal) ) { + $err = 'Invalid value - ' . htmlspecialchars($value,ENT_QUOTES); + } + else if ( $err != NULL ) { + $type3 = substr($this->_type, 0, 3); + if ( $type3 == 'fil' || $type3 == 'pat' ) { + $validator = new ConfValidation(); + $validator->chkAttr_file_val($this, $value, $err); + error_log('revalidate path ' . $value); + } + } + + if ( $err ) { + $cval->SetErr($err); + $o .= '*' . $this->check_split($err, 70) . '
    '; + } + + if ( $this->_href ) { + $link = $this->_hrefLink; + if ( strpos($link, '$V') ) { + $link = str_replace('$V', urlencode($value), $link); + } + $o .= ''; + } elseif ( $refUrl != NULL ) { + $o .= ''; + } + + + if ( $this->_type === 'bool' ) { + if ( $value === '1' ) { + $o .= 'Yes'; + } + elseif ( $value === '0' ) { + $o .= 'No'; + } + else { + $o .= 'Not Set'; + } + } + else if($this->_key == "note") { + $o .= ""; + } + elseif ( $this->_type === 'sel' || $this->_type === 'sel1' ) { + if ( $this->_maxVal != NULL && array_key_exists($value, $this->_maxVal) ) { + $o .= $this->_maxVal[$value]; + } + else { + $o .= htmlspecialchars($value,ENT_QUOTES); + } + } + elseif ( $this->_type === 'checkboxOr' ) { + if ($this->_minVal !== NULL && ($value === '' || $value === NULL) ) { + // has default value, for "Not set", set default val + $value = $this->_minVal; + } + foreach( $this->_maxVal as $val=>$name ) { + if ( ($value & $val) || ($value === $val) || ($value === '0' && $val === 0) ) { + $gif = 'checked.gif'; + } + else { + $gif = 'unchecked.gif'; + } + $o .= ' '; + $o .= $name . '   '; + } + } + elseif ( $this->_inputType === 'textarea1' ) { + $o .= ''; + } + elseif ( $this->_inputType === 'text' ) { + $o .= htmlspecialchars($this->check_split($value, 60), ENT_QUOTES); + } + elseif ( $this->_type == 'ctxseq' ) { + $o = $value . '   + ' ; + $o .= '/ - ' ; + } + elseif ( $this->_type == 'action' ) { + $o .= $value; + } + else { + $o .= htmlspecialchars($value); + } + + + if ( $this->_href || $refUrl != NULL) { + $o .= ''; + } + return $o; + } + + protected function getNote() + { + if ( $this->_note != NULL ) + return $this->_note; + if ( $this->_type == 'uint' ) + { + if ( $this->_maxVal ) + return 'number valid range: '. $this->_minVal . ' - ' . $this->_maxVal; + elseif ( $this->_minVal !== NULL ) + return 'number >= '. $this->_minVal ; + } + return null; + } + + protected function check_split($value, $width) + { + if ( $value == NULL ) + return NULL; + + $changed = false; + $val = explode(' ', $value); + for( $i = 0 ; $i < count($val) ; ++$i ) + { + if ( strlen($val[$i]) > $width ) + { + $val[$i] = chunk_split($val[$i], $width, ' '); + $changed = true; + } + } + if ( $changed ) + return implode(' ', $val); + else + return $value; + } + + + protected function genOptions($options, $selValue) + { + $o = ''; + if ( $options ) + { + foreach ( $options as $key => $value ) + { + $o .= '
diff --git a/dist/docs/css/hdoc.css b/dist/docs/css/hdoc.css index 2e411294a..e5480347c 100644 --- a/dist/docs/css/hdoc.css +++ b/dist/docs/css/hdoc.css @@ -90,7 +90,7 @@ ol li, ul li { FONT-WEIGHT: bold; FONT-SIZE: 14px; COLOR: #FFFFFF; BACKGROUND-COLOR: #555; background-image:linear-gradient(#666666,#555555); border-top-left-radius: 3px; border-top-right-radius: 3px; } .ht-label { - FONT-WEIGHT: bold; COLOR: #666699; FONT-SIZE: 13px; + FONT-WEIGHT: bold; COLOR: #555; FONT-SIZE: 13px; } .label-title { @@ -146,23 +146,23 @@ ol li, ul li { .cmd { PADDING-LEFT: 10px; PADDING-RIGHT: 10px; COLOR: #006600; } -.tag { COLOR: #339999; FONT-WEIGHT: bold } +.tag { COLOR: #116789; FONT-WEIGHT: bold } .val { COLOR: #000000; FONT-WEIGHT: bold } -.tagI { COLOR: #339999; FONT-WEIGHT: bold } -.tagI A { COLOR: #339999; TEXT-DECORATION: none } -.tagI A:visited { COLOR: #339999 } -.tagI A:hover { COLOR: #339999; TEXT-DECORATION: underline } +.tagI { COLOR: #116789; FONT-WEIGHT: bold } +.tagI A { COLOR: #116789; TEXT-DECORATION: none } +.tagI A:visited { COLOR: #116789 } +.tagI A:hover { COLOR: #ee9126; TEXT-DECORATION: underline } -.tagP { COLOR: #339999; FONT-WEIGHT: bold } -.tagP A { COLOR: #339999; TEXT-DECORATION: none } -.tagP A:visited { COLOR: #339999 } -.tagP A:hover { COLOR: #339999; TEXT-DECORATION: underline } +.tagP { COLOR: #116789; FONT-WEIGHT: bold } +.tagP A { COLOR: #116789; TEXT-DECORATION: none } +.tagP A:visited { COLOR: #116789 } +.tagP A:hover { COLOR: #ee9126; TEXT-DECORATION: underline } -.tagQ { COLOR: #339999; FONT-WEIGHT: bold } -.tagQ A { COLOR: #339999; TEXT-DECORATION: none } -.tagQ A:visited { COLOR: #339999 } -.tagQ A:hover { COLOR: #339999; TEXT-DECORATION: underline } +.tagQ { COLOR: #116789; FONT-WEIGHT: bold } +.tagQ A { COLOR: #116789; TEXT-DECORATION: none } +.tagQ A:visited { COLOR: #116789 } +.tagQ A:hover { COLOR: #ee9126; TEXT-DECORATION: underline } .copyright { FONT-SIZE: 11px; COLOR: #999999; TEXT-ALIGN: center; border-top: 1px solid #ddd; padding-top: 20px; diff --git a/dist/docs/index.html b/dist/docs/index.html index 51b6a3f6b..e36afa79c 100644 --- a/dist/docs/index.html +++ b/dist/docs/index.html @@ -11,7 +11,7 @@
-

Open LiteSpeed Web Server 1.0
+

Open LiteSpeed Web Server 1.2
Users' Manual
Rev. 1

diff --git a/dist/functions.sh b/dist/functions.sh index ec5ed3e76..b1a0f07f3 100755 --- a/dist/functions.sh +++ b/dist/functions.sh @@ -595,9 +595,12 @@ buildConfigFiles() { #sed -e "s/%ADMIN_PORT%/$ADMIN_PORT/" -e "s/%PHP_FCGI_PORT%/$ADMIN_PHP_PORT/" "$LSINSTALL_DIR/admin/conf/admin_config.xml.in" > "$LSINSTALL_DIR/admin/conf/admin_config.xml" - if [ $# -eq 1 ]; then + + if [ "x${SSL_HOSTNAME}" != "x" ] ; then + echo "SSL host is [${SSL_HOSTNAME}], use adminSSL" sed -e "s/%ADMIN_PORT%/$ADMIN_PORT/" -e "s/%SSL_HOSTNAME%/$SSL_HOSTNAME/" "$LSINSTALL_DIR/admin/conf/admin_config_ssl.xml.in" > "$LSINSTALL_DIR/admin/conf/admin_config.xml" else + echo "SSL host is [${SSL_HOSTNAME}], No adminssl" sed -e "s/%ADMIN_PORT%/$ADMIN_PORT/" "$LSINSTALL_DIR/admin/conf/admin_config.xml.in" > "$LSINSTALL_DIR/admin/conf/admin_config.xml" fi @@ -888,7 +891,7 @@ installation() rm -rf "$LSWS_HOME/admin/html.$VERSION" fi - util_mkdir "$SDIR_OWN" $DIR_MOD admin bin docs fcgi-bin php lib logs docs/css docs/img admin/logs add-ons share share/autoindex share/autoindex/icons admin/fcgi-bin admin/html.$VERSION admin/misc + util_mkdir "$SDIR_OWN" $DIR_MOD admin bin docs fcgi-bin php lib logs docs/css docs/img admin/logs add-ons share share/autoindex share/autoindex/icons admin/fcgi-bin admin/html.$VERSION admin/misc tmp tmp/ocspcache util_mkdir "$CONF_OWN" $SDIR_MOD conf conf/cert conf/templates admin/conf admin/tmp phpbuild util_mkdir "$SDIR_OWN" $SDIR_MOD admin/cgid admin/cgid/secret chgrp $WS_GROUP $LSWS_HOME/admin/tmp $LSWS_HOME/admin/cgid diff --git a/dist/install.sh b/dist/install.sh index fced56c76..13e0ea4c1 100755 --- a/dist/install.sh +++ b/dist/install.sh @@ -69,7 +69,7 @@ configRuby #Comment out the below two lines -echo "Target_Dir:$LSWS_HOME" "User:"$WS_USER "Group:$WS_GROUP" Admin:$ADMIN_USER Password:$PASS_ONE LSINSTALL_DIR:$LSINSTALL_DIR END +echo "Target_Dir:$LSWS_HOME User:$WS_USER Group:$WS_GROUP Admin:$ADMIN_USER Password:$PASS_ONE LSINSTALL_DIR:$LSINSTALL_DIR AdminSSL:$7 END" echo echo -e "\033[38;5;148mInstalling, please wait...\033[39m" @@ -77,13 +77,16 @@ echo -if [ "$7" = "yes" ] ; then +if [ "x$7" = "xyes" ] ; then + echo "Admin SSL enabled!" gen_selfsigned_cert ../adminssl.conf cp $LSINSTALL_DIR/${SSL_HOSTNAME}.crt $LSINSTALL_DIR/admin/conf/${SSL_HOSTNAME}.crt cp $LSINSTALL_DIR/${SSL_HOSTNAME}.key $LSINSTALL_DIR/admin/conf/${SSL_HOSTNAME}.key +else + echo "Admin SSL disabled!" fi -buildConfigFiles ${SSL_HOSTNAME} +buildConfigFiles installation rm $LSWS_HOME/bin/lshttpd diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc7239a24..377767d85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,10 +4,10 @@ cmake_minimum_required(VERSION 2.8) ########################################################################################## #If you want to link libUnitTest++, just un-comment out the following commands #AND YOU NEED TO INSTALL it to the directory /src/test/unittest-cpp/UnitTest++/ -#add_definitions(-DRUN_TEST) -#add_custom_target(Name ALL COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/test/unittest-cpp/UnitTest++) -#set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_SOURCE_DIR}/src/test/unittest-cpp/UnitTest++/libUnitTest++.a") -#set(libUnitTest libUnitTest++.a) +add_definitions(-DRUN_TEST) +add_custom_target(Name ALL COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/test/unittest-cpp/UnitTest++) +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_SOURCE_DIR}/src/test/unittest-cpp/UnitTest++/libUnitTest++.a") +set(libUnitTest libUnitTest++.a) ########################################################################################## @@ -17,7 +17,8 @@ cmake_minimum_required(VERSION 2.8) #INCLUDE( ${PROJECT_SOURCE_DIR}/CMakeModules/common.cmake) -#add_subdirectory(test) +add_subdirectory(test) +add_subdirectory(spdy) add_subdirectory(edio) add_subdirectory(socket) add_subdirectory(util) @@ -86,13 +87,22 @@ SET(util_STAT_SRCS test/util/base64test.cpp test/util/logfiletest.cpp test/util/stringmaptest.cpp + test/util/httpfetchtest.cpp +) + +SET(spdy_STAT_SRCS + test/spdy/spdyzlibfiltertest.cpp + test/spdy/spdyconnectiontest.cpp + test/spdy/dummiostream.cpp ) link_directories(/usr/local/lib ${PROJECT_SOURCE_DIR}/src/test/unittest-cpp/UnitTest++) -add_executable(openlitespeed ${openlitespeed_SRCS} ${edio_STAT_SRCS} ${extensions_STAT_SRCS} ${http_STAT_SRCS} ${socket_STAT_SRCS} ${util_STAT_SRCS}) +add_executable(openlitespeed ${openlitespeed_SRCS} ${edio_STAT_SRCS} + ${extensions_STAT_SRCS} ${http_STAT_SRCS} ${socket_STAT_SRCS} + ${util_STAT_SRCS} ${spdy_STAT_SRCS}) -target_link_libraries(openlitespeed main ssi http ssi registry cgi fcgi jk extensions lsapi proxy edio log4cxx socket sslpp util misc sysinfo GeoIP pthread dl ${libUnitTest} ) +target_link_libraries(openlitespeed main spdy ssi http ssi registry cgi fcgi jk extensions lsapi proxy edio log4cxx socket sslpp util misc sysinfo GeoIP pthread dl ${libUnitTest} ) install(TARGETS openlitespeed DESTINATION bin) @@ -100,5 +110,3 @@ install(TARGETS openlitespeed DESTINATION bin) ########### install files ############### - - diff --git a/src/Makefile.am b/src/Makefile.am index 72313a02a..a1e8f7e2d 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = openlitespeed openlitespeed_SOURCES = httpdtest.cpp main.cpp -openlitespeed_LDADD = ./main/libmain.a ./http/libhttp.a \ +openlitespeed_LDADD = ./main/libmain.a ./http/libhttp.a ./spdy/libspdy.a \ ./extensions/libextensions.a ./log4cxx/liblog4cxx.a \ ./socket/libsocket.a ./sslpp/libsslpp.a ./ssi/libssi.a ./edio/libedio.a ./util/libutil.a \ -lexpat -lssl -lz -lcrypto -lpcre -lGeoIP @@ -9,7 +9,7 @@ openlitespeed_LDADD = ./main/libmain.a ./http/libhttp.a \ AM_LDFLAGS = -L/usr/lib INCLUDES = -I$(top_srcdir)/src -SUBDIRS = socket util http sslpp ssi extensions log4cxx main edio +SUBDIRS = socket util http spdy sslpp ssi extensions log4cxx main edio # the library search path. diff --git a/src/Makefile.in b/src/Makefile.in index c4d883996..31457fcd3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -68,9 +68,9 @@ PROGRAMS = $(bin_PROGRAMS) am_openlitespeed_OBJECTS = httpdtest.$(OBJEXT) main.$(OBJEXT) openlitespeed_OBJECTS = $(am_openlitespeed_OBJECTS) openlitespeed_DEPENDENCIES = ./main/libmain.a ./http/libhttp.a \ - ./extensions/libextensions.a ./log4cxx/liblog4cxx.a \ - ./socket/libsocket.a ./sslpp/libsslpp.a ./ssi/libssi.a \ - ./edio/libedio.a ./util/libutil.a + ./spdy/libspdy.a ./extensions/libextensions.a \ + ./log4cxx/liblog4cxx.a ./socket/libsocket.a ./sslpp/libsslpp.a \ + ./ssi/libssi.a ./edio/libedio.a ./util/libutil.a openlitespeed_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ $(openlitespeed_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ @@ -239,14 +239,14 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ openlitespeed_SOURCES = httpdtest.cpp main.cpp -openlitespeed_LDADD = ./main/libmain.a ./http/libhttp.a \ +openlitespeed_LDADD = ./main/libmain.a ./http/libhttp.a ./spdy/libspdy.a \ ./extensions/libextensions.a ./log4cxx/liblog4cxx.a \ ./socket/libsocket.a ./sslpp/libsslpp.a ./ssi/libssi.a ./edio/libedio.a ./util/libutil.a \ -lexpat -lssl -lz -lcrypto -lpcre -lGeoIP AM_LDFLAGS = -L/usr/lib INCLUDES = -I$(top_srcdir)/src -SUBDIRS = socket util http sslpp ssi extensions log4cxx main edio +SUBDIRS = socket util http spdy sslpp ssi extensions log4cxx main edio # the library search path. openlitespeed_LDFLAGS = $(all_libraries) diff --git a/src/config.h.cmake b/src/config.h.cmake index e69de29bb..c1d624ccf 100644 --- a/src/config.h.cmake +++ b/src/config.h.cmake @@ -0,0 +1,8 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define PACKAGE_VERSION "1.2" +#define LS_ENABLE_SPDY 1 + +#endif + diff --git a/src/config.h.in b/src/config.h.in index ec8c90ebb..dc2b78949 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -198,6 +198,9 @@ slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK +/* Define if need spdy feature */ +#undef LS_ENABLE_SPDY + /* Define to 1 if assertions should be disabled. */ #undef NDEBUG diff --git a/src/edio/bufferedos.h b/src/edio/bufferedos.h index 94630759e..490868857 100644 --- a/src/edio/bufferedos.h +++ b/src/edio/bufferedos.h @@ -62,3 +62,6 @@ class BufferedOS : public OutputStream }; #endif + + + diff --git a/src/edio/epoll.cpp b/src/edio/epoll.cpp index d05ecf44d..417d88505 100644 --- a/src/edio/epoll.cpp +++ b/src/edio/epoll.cpp @@ -258,7 +258,7 @@ int epoll::waitAndProcessEvents( int iTimeoutMilliSec ) if ( fd != -1 ) { EventReactor * pReactor = m_reactorIndex.get( fd ); - if ( pReactor && (pReactor->getAssignedRevent() == p->events ) ) + if ( pReactor && (pReactor->getAssignedRevent() == (int)p->events ) ) { if ( p->events & POLLHUP ) pReactor->incHupCounter(); diff --git a/src/edio/outputstream.cpp b/src/edio/outputstream.cpp index 8d16b728d..8b4b0da40 100644 --- a/src/edio/outputstream.cpp +++ b/src/edio/outputstream.cpp @@ -23,7 +23,7 @@ #include #include -int OutputStream::writev( IOVec& vec ) +int OutputStream::writevToWrite( IOVec& vec ) { int ret = 0; int bufSize; @@ -46,5 +46,21 @@ int OutputStream::writev( IOVec& vec ) return ret; } +int OutputStream::writev( IOVec& vec ) +{ + int bufSize; + int count = vec.len(); + int total = 0; + const struct iovec * vector = vec.get(); + for( ; count > 0; --count, ++vector ) + { + const char * pBuf =( const char *) vector->iov_base; + bufSize = vector->iov_len; + if (( pBuf != NULL )&&( bufSize > 0 )) + total += bufSize; + } + + return writev( vec, total ); +} diff --git a/src/edio/outputstream.h b/src/edio/outputstream.h index 5e0e38acc..e07953596 100644 --- a/src/edio/outputstream.h +++ b/src/edio/outputstream.h @@ -30,6 +30,7 @@ class OutputStream virtual int writev( IOVec& vector, int total ) = 0; virtual int flush() = 0; virtual int close() = 0; + int writevToWrite( IOVec& vector ); }; diff --git a/src/edio/reactorindex.cpp b/src/edio/reactorindex.cpp index 52bb9786f..024b2ac6a 100644 --- a/src/edio/reactorindex.cpp +++ b/src/edio/reactorindex.cpp @@ -69,7 +69,7 @@ void ReactorIndex::timerExec() { if ( m_pIndexes[i] ) { - if ( m_pIndexes[i]->getfd() == i ) + if ( m_pIndexes[i]->getfd() == (int)i ) m_pIndexes[i]->onTimer(); else { diff --git a/src/extensions/CMakeLists.txt b/src/extensions/CMakeLists.txt index 75a0f0a0b..1e5721b77 100644 --- a/src/extensions/CMakeLists.txt +++ b/src/extensions/CMakeLists.txt @@ -23,6 +23,7 @@ SET(extensions_STAT_SRCS extworker.cpp extconn.cpp extworkerconfig.cpp + l4conn.cpp ) add_library(extensions STATIC ${extensions_STAT_SRCS}) diff --git a/src/extensions/Makefile.am b/src/extensions/Makefile.am index e98ca4aa5..c9b4b12f8 100755 --- a/src/extensions/Makefile.am +++ b/src/extensions/Makefile.am @@ -6,7 +6,7 @@ INCLUDES = -I$(top_srcdir)/src libextensions_a_METASOURCES = AUTO libextensions_a_SOURCES = loadbalancer.cpp localworkerconfig.cpp localworker.cpp pidlist.cpp iprocessortimer.cpp httpextprocessor.cpp \ - extrequest.cpp extworker.cpp extconn.cpp extworkerconfig.cpp \ + extrequest.cpp extworker.cpp extconn.cpp extworkerconfig.cpp l4conn.cpp \ cgi/lscgid.cpp cgi/suexec.cpp cgi/cgidreq.cpp cgi/cgidconfig.cpp cgi/cgidworker.cpp cgi/cgidconn.cpp \ fcgi/fcgienv.cpp fcgi/fcgiappconfig.cpp fcgi/fcgiapp.cpp fcgi/fcginamevaluepair.cpp fcgi/fcgiconnection.cpp fcgi/fcgirecord.cpp \ jk/jkajp13.cpp jk/jworker.cpp jk/jworkerconfig.cpp jk/jconn.cpp \ diff --git a/src/extensions/Makefile.in b/src/extensions/Makefile.in index fd847eb6b..966657ed1 100644 --- a/src/extensions/Makefile.in +++ b/src/extensions/Makefile.in @@ -72,16 +72,16 @@ am_libextensions_a_OBJECTS = loadbalancer.$(OBJEXT) \ pidlist.$(OBJEXT) iprocessortimer.$(OBJEXT) \ httpextprocessor.$(OBJEXT) extrequest.$(OBJEXT) \ extworker.$(OBJEXT) extconn.$(OBJEXT) \ - extworkerconfig.$(OBJEXT) lscgid.$(OBJEXT) suexec.$(OBJEXT) \ - cgidreq.$(OBJEXT) cgidconfig.$(OBJEXT) cgidworker.$(OBJEXT) \ - cgidconn.$(OBJEXT) fcgienv.$(OBJEXT) fcgiappconfig.$(OBJEXT) \ - fcgiapp.$(OBJEXT) fcginamevaluepair.$(OBJEXT) \ - fcgiconnection.$(OBJEXT) fcgirecord.$(OBJEXT) \ - jkajp13.$(OBJEXT) jworker.$(OBJEXT) jworkerconfig.$(OBJEXT) \ - jconn.$(OBJEXT) proxyconfig.$(OBJEXT) proxyworker.$(OBJEXT) \ - proxyconn.$(OBJEXT) extappregistry.$(OBJEXT) \ - lsapiworker.$(OBJEXT) lsapireq.$(OBJEXT) lsapiconn.$(OBJEXT) \ - lsapiconfig.$(OBJEXT) + extworkerconfig.$(OBJEXT) l4conn.$(OBJEXT) lscgid.$(OBJEXT) \ + suexec.$(OBJEXT) cgidreq.$(OBJEXT) cgidconfig.$(OBJEXT) \ + cgidworker.$(OBJEXT) cgidconn.$(OBJEXT) fcgienv.$(OBJEXT) \ + fcgiappconfig.$(OBJEXT) fcgiapp.$(OBJEXT) \ + fcginamevaluepair.$(OBJEXT) fcgiconnection.$(OBJEXT) \ + fcgirecord.$(OBJEXT) jkajp13.$(OBJEXT) jworker.$(OBJEXT) \ + jworkerconfig.$(OBJEXT) jconn.$(OBJEXT) proxyconfig.$(OBJEXT) \ + proxyworker.$(OBJEXT) proxyconn.$(OBJEXT) \ + extappregistry.$(OBJEXT) lsapiworker.$(OBJEXT) \ + lsapireq.$(OBJEXT) lsapiconn.$(OBJEXT) lsapiconfig.$(OBJEXT) libextensions_a_OBJECTS = $(am_libextensions_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -216,7 +216,7 @@ noinst_LIBRARIES = libextensions.a INCLUDES = -I$(top_srcdir)/src libextensions_a_METASOURCES = AUTO libextensions_a_SOURCES = loadbalancer.cpp localworkerconfig.cpp localworker.cpp pidlist.cpp iprocessortimer.cpp httpextprocessor.cpp \ - extrequest.cpp extworker.cpp extconn.cpp extworkerconfig.cpp \ + extrequest.cpp extworker.cpp extconn.cpp extworkerconfig.cpp l4conn.cpp \ cgi/lscgid.cpp cgi/suexec.cpp cgi/cgidreq.cpp cgi/cgidconfig.cpp cgi/cgidworker.cpp cgi/cgidconn.cpp \ fcgi/fcgienv.cpp fcgi/fcgiappconfig.cpp fcgi/fcgiapp.cpp fcgi/fcginamevaluepair.cpp fcgi/fcgiconnection.cpp fcgi/fcgirecord.cpp \ jk/jkajp13.cpp jk/jworker.cpp jk/jworkerconfig.cpp jk/jconn.cpp \ @@ -293,6 +293,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jkajp13.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jworker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jworkerconfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/l4conn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loadbalancer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localworker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localworkerconfig.Po@am__quote@ diff --git a/src/extensions/cgi/cgidconn.cpp b/src/extensions/cgi/cgidconn.cpp index 8016855b6..4daeac34b 100644 --- a/src/extensions/cgi/cgidconn.cpp +++ b/src/extensions/cgi/cgidconn.cpp @@ -244,7 +244,6 @@ int CgidConn::buildSSIExecHeader() { static unsigned int s_id = 0; HttpConnection * pConn = getConnector()->getHttpConn(); - lscgid_req * pHeader = m_req.getCgidReq(); HttpReq * pReq = pConn->getReq(); const char * pReal; const AutoStr2 * psChroot; @@ -309,7 +308,6 @@ int CgidConn::buildReqHeader() { static unsigned int s_id = 0; HttpConnection * pConn = getConnector()->getHttpConn(); - lscgid_req * pHeader = m_req.getCgidReq(); HttpReq * pReq = pConn->getReq(); const char * pQueryString = pReq->getQueryString(); const char * pQsEnd = pReq->getQueryString() + pReq->getQueryStringLen(); @@ -343,7 +341,6 @@ int CgidConn::buildReqHeader() ret = 0; } int priority = ((CgidWorker *)getWorker())->getConfig().getPriority(); - int pathLen = realPath->len(); m_req.buildReqHeader( uid, gid, priority, pChroot, ret, pReal, pReq->getRealPath()->len(), ((CgidWorker *)getWorker())->getConfig().getRLimits() ); diff --git a/src/extensions/cgi/cgidconn.h b/src/extensions/cgi/cgidconn.h index 11e5458ce..3eabbd734 100644 --- a/src/extensions/cgi/cgidconn.h +++ b/src/extensions/cgi/cgidconn.h @@ -63,8 +63,7 @@ class CgidConn : public ExtConn virtual int flush(); virtual void cleanUp(); virtual void dump(); - virtual int writeConnStatus( char * pBuf, int len ) - {} + virtual int writeConnStatus( char * pBuf, int len ) { return 0; } //{ return ExtConn::writeConnStatus( pBuf, len ); } virtual int sendReqHeader(); diff --git a/src/extensions/cgi/cgidreq.cpp b/src/extensions/cgi/cgidreq.cpp index 82b6f411a..0877a4534 100644 --- a/src/extensions/cgi/cgidreq.cpp +++ b/src/extensions/cgi/cgidreq.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ #include "cgidreq.h" -#include +#include #include #include @@ -190,10 +190,7 @@ int CgidReq::finalize( int req_id, const char * pSecret, int type ) RAND_pseudo_bytes( pHeader->m_nonce, 16 ); memmove( pHeader->m_md5, pSecret, 16 ); - MD5_CTX md5_ctx; - MD5_Init( &md5_ctx ); - MD5_Update( &md5_ctx, pHeader, sizeof( lscgid_req ) ); - MD5_Final( pHeader->m_md5, &md5_ctx ); + StringTool::getMd5( (const char *)pHeader, sizeof( lscgid_req ), pHeader->m_md5 ); return 0; } diff --git a/src/extensions/cgi/cgidworker.cpp b/src/extensions/cgi/cgidworker.cpp index 2f7786d00..e3c82253b 100644 --- a/src/extensions/cgi/cgidworker.cpp +++ b/src/extensions/cgi/cgidworker.cpp @@ -134,7 +134,7 @@ int CgidWorker::spawnCgid( int fd, char * pData, const char *secret ) const char * pChroot = ""; if ( HttpGlobals::s_psChroot ) pChroot = HttpGlobals::s_psChroot->c_str(); - int n = snprintf( pData, 255, "uds:/%s%s", pChroot, + snprintf( pData, 255, "uds:/%s%s", pChroot, getConfig().getServerAddrUnixSock() ); pid = fork(); //in child diff --git a/src/extensions/cgi/lscgid.cpp b/src/extensions/cgi/lscgid.cpp index dd6e19e43..480a9812e 100644 --- a/src/extensions/cgi/lscgid.cpp +++ b/src/extensions/cgi/lscgid.cpp @@ -22,7 +22,7 @@ #endif #include "lscgid.h" -#include +#include #include #include @@ -496,15 +496,12 @@ static int process_req_data( lscgid_t * cgi_req ) static int process_req_header( lscgid_t *cgi_req ) { - MD5_CTX md5ctx; char achMD5[16]; int totalBufLen; memmove( achMD5, cgi_req->m_data.m_md5, 16 ); memmove( cgi_req->m_data.m_md5, s_pSecret, 16 ); - MD5_Init( &md5ctx ); - MD5_Update( &md5ctx, (unsigned char *)&cgi_req->m_data, - sizeof( lscgid_req ) ); - MD5_Final( cgi_req->m_data.m_md5, &md5ctx); + StringTool::getMd5((const char *)&cgi_req->m_data, + sizeof( lscgid_req ), cgi_req->m_data.m_md5); if ( memcmp( cgi_req->m_data.m_md5, achMD5, 16 ) != 0 ) { s_pError = "lscgid: request validation failed!"; @@ -512,7 +509,7 @@ static int process_req_header( lscgid_t *cgi_req ) } totalBufLen = cgi_req->m_data.m_szData + sizeof( char * ) * (cgi_req->m_data.m_nargv + cgi_req->m_data.m_nenv); - if ( totalBufLen < sizeof( s_sDataBuf ) ) + if ( (unsigned int)totalBufLen < sizeof( s_sDataBuf ) ) { cgi_req->m_pBuf = s_sDataBuf; } @@ -661,7 +658,6 @@ static int new_conn( int fd ) static int run(int fdServerSock) { int ret; - long tmBegin = time( NULL ); struct pollfd pfd; pfd.fd = fdServerSock; pfd.events = POLLIN; diff --git a/src/extensions/cgi/suexec.cpp b/src/extensions/cgi/suexec.cpp index 6a55369f0..6d0c6d3ef 100644 --- a/src/extensions/cgi/suexec.cpp +++ b/src/extensions/cgi/suexec.cpp @@ -214,7 +214,7 @@ int SUExec::checkLScgid( const char * path ) } static char sDefaultPath[] = "PATH=/bin:/usr/bin:/usr/local/bin"; -static char sLVE[] = "LVE_ENABLE=1"; +//static char sLVE[] = "LVE_ENABLE=1"; int SUExec::suEXEC( const char * pServerRoot, int * pfd, int listenFd, char * const * pArgv, char * const * env, const RLimits * pLimits ) @@ -385,10 +385,6 @@ int send_fd(int fd, int sendfd) int SUExec::cgidSuEXEC( const char * pServerRoot, int * pfd, int listenFd, char * const * pArgv, char * const * env, const RLimits * pLimits ) { - char *pEnv[3]; - char achExec[2048]; - char sockAddr[256]; - int ret; int pid = -1; while( 1 ) { @@ -404,24 +400,17 @@ int SUExec::cgidSuEXEC( const char * pServerRoot, int * pfd, int listenFd, break; ++env; } - pEnv[0] = sDefaultPath; #ifdef _HAS_LVE_ if (( HttpGlobals::s_pCgid->getLVE() )&&(m_req.getCgidReq()->m_uid )) { sLVE[11] = HttpGlobals::s_pCgid->getLVE() + '0'; - pEnv[1] = sLVE; - pEnv[2] = 0; } - else - pEnv[1] = 0; -#else - pEnv[1] = 0; #endif int fdReq = -1; - ret = CoreSocket::connect( + CoreSocket::connect( HttpGlobals::s_pCgid->getConfig().getServerAddr(), 0, &fdReq, 1 ); diff --git a/src/extensions/extworker.cpp b/src/extensions/extworker.cpp index e46cd4b62..01e60a07c 100644 --- a/src/extensions/extworker.cpp +++ b/src/extensions/extworker.cpp @@ -454,6 +454,7 @@ int ExtWorker::generateRTReport( int fd, const char * pTypeName ) char * p; char achBuf[4096]; p = achBuf; + detectDiedPid(); m_connPool.for_each_conn( onConnTimer ); m_reqStats.finalizeRpt(); int inUseConn = m_connPool.getTotalConns() - m_connPool.getFreeConns(); diff --git a/src/extensions/extworker.h b/src/extensions/extworker.h index 58d69c926..94fa26539 100644 --- a/src/extensions/extworker.h +++ b/src/extensions/extworker.h @@ -138,6 +138,7 @@ class ExtWorker : public HttpHandler virtual int addNewProcess() { return 0; } virtual int startOnDemond(int force ) { return 0; } virtual int runOnStartUp() { return 0; } + virtual void detectDiedPid() {} bool canStop() { return m_connPool.getTotalConns() == m_connPool.getFreeConns(); diff --git a/src/extensions/l4conn.cpp b/src/extensions/l4conn.cpp new file mode 100644 index 000000000..ad5a8a9a8 --- /dev/null +++ b/src/extensions/l4conn.cpp @@ -0,0 +1,318 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#include "l4conn.h" +#include "http/l4handler.h" +#include +#include +#include + +#include +#include + +#include +#include +#include + +int L4conn::onEventDone() +{ + switch( m_iState ) + { + case CLOSING: + m_pL4Handler->closeBothConnection(); + break; + } + return 0; +} + +int L4conn::onError() +{ + int error = errno; + int ret = getSockError( &error ); + if (( ret ==-1 )||( error != 0 )) + { + if ( ret != -1 ) + errno = error; + } + if ( D_ENABLED( DL_LESS ) ) + LOG_D(( getLogger(), "[%s] L4conn::onError()", getLogId() )); + if ( error != 0 ) + { + m_iState = CLOSING; + //doError( error ); + } + else + onRead(); + return -1; +} + +int L4conn::onWrite() +{ + if ( D_ENABLED( DL_LESS ) ) + LOG_D(( getLogger(), "[%s] L4conn::onWrite()", getLogId() )); + + int ret; + switch( m_iState ) + { + case CONNECTING: + ret = onInitConnected(); + if ( ret ) + break; + //fall through + case PROCESSING: + ret = doWrite(); + break; + case CLOSING: + case DISCONNECTED: + return 0; + default: + return 0; + } + if ( ret == -1 ) + { + m_pL4Handler->closeBothConnection(); + } + return ret; +} + +int L4conn::onInitConnected() +{ + int error; + int ret = getSockError( &error ); + if (( ret == -1 )||( error != 0 )) + { + if ( ret != -1 ) + errno = error; + return -1; + } + m_iState = PROCESSING; +// if ( D_ENABLED( DL_LESS ) ) +// { +// char achSockAddr[128]; +// char achAddr[128] = ""; +// int port = 0; +// socklen_t len = 128; +// +// if ( getsockname( getfd(), (struct sockaddr *)achSockAddr, &len ) == 0 ) +// { +// GSockAddr::ntop( (struct sockaddr *)achSockAddr, achAddr, 128 ); +// port = GSockAddr::getPort( (struct sockaddr *)achSockAddr ); +// } + +// LOG_D(( getLogger(), "[%s] connected to [%s] on local addres [%s:%d]!", getLogId(), +// m_pWorker->getURL(), achAddr, port )); +// } + return 0; +} + + +int L4conn::onRead() +{ + if ( D_ENABLED( DL_LESS ) ) + LOG_D(( getLogger(), "[%s] L4conn::onRead() state: %d", getLogId(), m_iState )); + + int ret; + switch( m_iState ) + { + case CONNECTING: + ret = onInitConnected(); + break; + case PROCESSING: + ret = doRead(); + break; + case CLOSING: + case DISCONNECTED: + return 0; + default: + // Not suppose to happen; + return 0; + } + if ( ret == -1 ) + { + m_pL4Handler->closeBothConnection(); + } + return ret; +} + +int L4conn::close() +{ + if (m_iState != DISCONNECTED) + { + m_iState = DISCONNECTED; + if ( D_ENABLED( DL_LESS ) ) + LOG_D(( getLogger(), "[%s] [ExtConn] close()", getLogId() )); + EdStream::close(); + delete m_buf; + } + + return 0; +} + +L4conn::L4conn(L4Handler* pL4Handler) : m_iState( 0 ) +{ + m_pL4Handler = pL4Handler; + m_buf = new LoopBuf(MAX_OUTGOING_BUF_ZISE); +} + +L4conn::~L4conn() +{ + if (m_iState != DISCONNECTED) + close(); +} + +int L4conn::init(const GSockAddr *pGSockAddr) +{ + int ret = connectEx(pGSockAddr); + + if ( D_ENABLED( DL_LESS ) ) + LOG_D (( getLogger(), "[%s] [L4conn] init ret = [%d]...", getLogId(), ret )); + + return ret; +} + +int L4conn::connectEx(const GSockAddr *pGSockAddr) +{ + int fd; + int ret; + Multiplexer *pMpl = HttpGlobals::getMultiplexer(); + ret = CoreSocket::connect( *pGSockAddr, pMpl->getFLTag(), &fd, 0 ); + if (( fd == -1 )&&( errno == ECONNREFUSED )) + { + ret = CoreSocket::connect( *pGSockAddr, pMpl->getFLTag(), &fd, 0 ); + } + + if ( fd != -1 ) + { + if ( D_ENABLED( DL_LESS ) ) + LOG_D(( getLogger(), "[%s] [L4conn] connecting to [%s]...", + getLogId(), pGSockAddr->toString() )); + + ::fcntl( fd, F_SETFD, FD_CLOEXEC ); + EdStream::init ( fd, pMpl, POLLIN|POLLOUT|POLLHUP|POLLERR ); + if ( ret == 0 ) + { + m_iState = PROCESSING; + onWrite(); + } + else + m_iState = CONNECTING; + return 0; + } + return -1; +} + +int L4conn::doRead() +{ + bool empty = m_pL4Handler->getBuf()->empty(); + int space; + + if ( (space = m_pL4Handler->getBuf()->contiguous()) > 0) + { + int n = read(m_pL4Handler->getBuf()->end(), space); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] [L4conn] doRead [%d]...", + getLogId(), n )); + } + + if (n > 0) + { + m_pL4Handler->getBuf()->used(n); + } + else if (n < 0) + { + m_pL4Handler->closeBothConnection(); + return -1; + } + } + + if ( !m_pL4Handler->getBuf()->empty() ) + { + m_pL4Handler->doWrite(); + if ( !m_pL4Handler->getBuf()->empty() && empty) + m_pL4Handler->continueWrite(); + + if (m_pL4Handler->getBuf()->available() <= 0 ) + { + suspendRead(); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] [L4conn] suspendRead", + getLogId() )); + } + } + } + return 0; +} + +int L4conn::doWrite() +{ + bool full = ((getBuf()->available() == 0) ? true : false); + int length; + + while ((length = getBuf()->blockSize()) > 0 ) + { + int n = write(getBuf()->begin(), length); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] [L4conn] doWrite [%d of %d]...", + getLogId(), n, length )); + } + + if (n > 0) + { + getBuf()->pop_front(n); + } + else if ( n == 0 ) + break; + else // if (n < 0) + { + m_pL4Handler->closeBothConnection(); + return -1; + } + + } + + if (getBuf()->available() != 0) + { + if (full) + m_pL4Handler->continueRead(); + + if ( getBuf()->empty() ) + { + suspendWrite(); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] [L4conn] suspendWrite && m_pL4Handler->continueRead", + getLogId() )); + } + } + } + + return 0; +} + +LOG4CXX_NS::Logger * L4conn::getLogger() const +{ + return m_pL4Handler->getLogger(); +} + +const char * L4conn::getLogId() +{ + return m_pL4Handler->getLogId(); +} diff --git a/src/extensions/l4conn.h b/src/extensions/l4conn.h new file mode 100644 index 000000000..e5e9d3eb1 --- /dev/null +++ b/src/extensions/l4conn.h @@ -0,0 +1,73 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#ifndef L4CONN_H +#define L4CONN_H + +#include +#include +#define MAX_OUTGOING_BUF_ZISE 8192 +#include +#include "socket/gsockaddr.h" + +class L4Handler; + +class L4conn : public EdStream +{ +public: + L4conn(L4Handler* pL4Handler); + virtual ~L4conn(); + + int onEventDone(); + int onError(); + int onWrite(); + int onRead(); + int close(); + int readv(iovec* vector, size_t count) { return 0; } + + int onInitConnected(); + + int doRead(); + int doWrite(); + + + //Return 0 is OK + int init(const GSockAddr *pGSockAddr); + int connectEx(const GSockAddr *pGSockAddr); + + LoopBuf* getBuf() { return m_buf; } + +private: + char m_iState; + L4Handler* m_pL4Handler; + LoopBuf * m_buf; + + enum + { + DISCONNECTED, + CONNECTING, + PROCESSING, + CLOSING, + }; + + LOG4CXX_NS::Logger * getLogger() const; + const char * getLogId(); + +}; + +#endif // L4CONN_H diff --git a/src/extensions/localworker.cpp b/src/extensions/localworker.cpp index 892404233..2a3b2687f 100644 --- a/src/extensions/localworker.cpp +++ b/src/extensions/localworker.cpp @@ -117,6 +117,7 @@ void LocalWorker::cleanStopPids( ) if (( kill( pid, 0 ) == -1 )&&( errno == ESRCH )) { m_pidListStop->erase( iterDel ); + PidRegistry::remove( pid ); continue; } if ( delta > KILL_TIMEOUT ) @@ -145,6 +146,27 @@ void LocalWorker::cleanStopPids( ) } } +void LocalWorker::detectDiedPid() +{ + PidList::iterator iter; + for( iter = m_pidList->begin(); iter != m_pidList->end(); ) + { + pid_t pid = (pid_t)(long)iter->first(); + if (( kill( pid, 0 ) == -1 )&& (errno == ESRCH )) + { + LOG_INFO(( "Process with PID: %d is dead ", pid )); + PidList::iterator iterNext = m_pidList->next( iter ); + m_pidList->erase( iter ); + PidRegistry::remove( pid ); + + iter = iterNext; + + } + else + iter = m_pidList->next( iter ); + } +} + void LocalWorker::addPid( pid_t pid ) { m_pidList->insert( (void *)(unsigned long )pid, this ); @@ -281,65 +303,65 @@ int LocalWorker::getCurInstances() const // } -static int workerSUExec( LocalWorkerConfig& config, int fd ) -{ - const HttpVHost * pVHost = config.getVHost(); - if (( !HttpGlobals::s_pSUExec )||( !pVHost )) - return -1; - int mode = pVHost->getRootContext().getSetUidMode(); - if ( mode != UID_DOCROOT ) - return -1; - uid_t uid = pVHost->getUid(); - gid_t gid = pVHost->getGid(); - if (( uid == HttpGlobals::s_uid )&& - ( gid == HttpGlobals::s_gid )) - return -1; - - if (( uid < HttpGlobals::s_uidMin )|| - ( gid < HttpGlobals::s_gidMin )) - { - LOG_INFO(( "[VHost:%s] Fast CGI [%s]: suExec access denied," - " UID or GID of VHost document root is smaller " - "than minimum UID, GID configured. ", pVHost->getName(), - config.getName() )); - return -1; - } - const char * pChroot = NULL; - int chrootLen = 0; -// if ( HttpGlobals::s_psChroot ) -// { -// pChroot = HttpGlobals::s_psChroot->c_str(); -// chrootLen = HttpGlobals::s_psChroot->len(); -// } - char achBuf[4096]; - memccpy( achBuf, config.getCommand(), 0, 4096 ); - char * argv[256]; - char * pDir ; - SUExec::buildArgv( achBuf, &pDir, argv, 256 ); - if ( pDir ) - *(argv[0]-1) = '/'; - else - pDir = argv[0]; - HttpGlobals::s_pSUExec->prepare( uid, gid, config.getPriority(), - pChroot, chrootLen, - pDir, strlen( pDir ), config.getRLimits() ); - int rfd = -1; - int pid = HttpGlobals::s_pSUExec->suEXEC( HttpGlobals::s_pServerRoot, &rfd, fd, argv, - config.getEnv()->get(), NULL ); -// if ( pid != -1) -// { -// char achBuf[2048]; -// int ret; -// while( ( ret = read( rfd, achBuf, 2048 )) > 0 ) -// { -// write( 2, achBuf, ret ); -// } -// } - if ( rfd != -1 ) - close( rfd ); - - return pid; -} +// static int workerSUExec( LocalWorkerConfig& config, int fd ) +// { +// const HttpVHost * pVHost = config.getVHost(); +// if (( !HttpGlobals::s_pSUExec )||( !pVHost )) +// return -1; +// int mode = pVHost->getRootContext().getSetUidMode(); +// if ( mode != UID_DOCROOT ) +// return -1; +// uid_t uid = pVHost->getUid(); +// gid_t gid = pVHost->getGid(); +// if (( uid == HttpGlobals::s_uid )&& +// ( gid == HttpGlobals::s_gid )) +// return -1; +// +// if (( uid < HttpGlobals::s_uidMin )|| +// ( gid < HttpGlobals::s_gidMin )) +// { +// LOG_INFO(( "[VHost:%s] Fast CGI [%s]: suExec access denied," +// " UID or GID of VHost document root is smaller " +// "than minimum UID, GID configured. ", pVHost->getName(), +// config.getName() )); +// return -1; +// } +// const char * pChroot = NULL; +// int chrootLen = 0; +// // if ( HttpGlobals::s_psChroot ) +// // { +// // pChroot = HttpGlobals::s_psChroot->c_str(); +// // chrootLen = HttpGlobals::s_psChroot->len(); +// // } +// char achBuf[4096]; +// memccpy( achBuf, config.getCommand(), 0, 4096 ); +// char * argv[256]; +// char * pDir ; +// SUExec::buildArgv( achBuf, &pDir, argv, 256 ); +// if ( pDir ) +// *(argv[0]-1) = '/'; +// else +// pDir = argv[0]; +// HttpGlobals::s_pSUExec->prepare( uid, gid, config.getPriority(), +// pChroot, chrootLen, +// pDir, strlen( pDir ), config.getRLimits() ); +// int rfd = -1; +// int pid = HttpGlobals::s_pSUExec->suEXEC( HttpGlobals::s_pServerRoot, &rfd, fd, argv, +// config.getEnv()->get(), NULL ); +// // if ( pid != -1) +// // { +// // char achBuf[2048]; +// // int ret; +// // while( ( ret = read( rfd, achBuf, 2048 )) > 0 ) +// // { +// // write( 2, achBuf, ret ); +// // } +// // } +// if ( rfd != -1 ) +// close( rfd ); +// +// return pid; +// } int LocalWorker::workerExec( LocalWorkerConfig& config, int fd ) { @@ -359,9 +381,9 @@ int LocalWorker::workerExec( LocalWorkerConfig& config, int fd ) { uid = config.getUid(); gid = config.getGid(); - if ( uid == -1 ) + if ( (int)uid == -1 ) uid = HttpGlobals::s_uid; - if ( gid == -1 ) + if ( (int)gid == -1 ) gid = HttpGlobals::s_gid; } } diff --git a/src/extensions/localworker.h b/src/extensions/localworker.h index 88780fd8f..fee7decab 100644 --- a/src/extensions/localworker.h +++ b/src/extensions/localworker.h @@ -44,6 +44,7 @@ class LocalWorker : public ExtWorker int startOnDemond( int force); void cleanStopPids(); + void detectDiedPid(); void setfd( int fd ) { m_fdApp = fd; } int getfd() const { return m_fdApp; } diff --git a/src/extensions/registry/extappregistry.cpp b/src/extensions/registry/extappregistry.cpp index 1b0ce7670..52337a0d6 100644 --- a/src/extensions/registry/extappregistry.cpp +++ b/src/extensions/registry/extappregistry.cpp @@ -365,18 +365,20 @@ void PidRegistry::add( pid_t pid, ExtWorker * pApp, long tm ) s_pSimpleList->add( pid, getpid(), pApp ); } -void PidRegistry::remove( pid_t pid) +ExtWorker * PidRegistry::remove( pid_t pid) { + ExtWorker * pWorker = NULL; if ( s_pSimpleList ) { - ExtWorker * pWorker = s_pSimpleList->remove( pid ); + pWorker = s_pSimpleList->remove( pid ); s_pidList()->remove( pid ); - if ( pWorker ) - pWorker->removePid( pid ); } + return pWorker; } + + void PidRegistry::setSimpleList( PidSimpleList * pList ) { s_pSimpleList = pList; diff --git a/src/extensions/registry/extappregistry.h b/src/extensions/registry/extappregistry.h index e83218849..97dfd49a2 100644 --- a/src/extensions/registry/extappregistry.h +++ b/src/extensions/registry/extappregistry.h @@ -82,7 +82,7 @@ class PidRegistry static void setSimpleList( PidSimpleList * pList ); static void add( pid_t pid, ExtWorker * pApp, long tm ); - static void remove( pid_t pid); + static ExtWorker * remove( pid_t pid); static void markToStop( pid_t pid, int kill_type ); }; diff --git a/src/http/CMakeLists.txt b/src/http/CMakeLists.txt index 9f3553670..412a8011f 100644 --- a/src/http/CMakeLists.txt +++ b/src/http/CMakeLists.txt @@ -68,7 +68,7 @@ SET(http_STAT_SRCS reqhandler.cpp httpvhost.cpp httpresourcemanager.cpp - httpiolink.cpp + ntwkiolink.cpp httpmethod.cpp httpver.cpp httpstatuscode.cpp @@ -83,6 +83,10 @@ SET(http_STAT_SRCS iptogeo.cpp moov.cpp #requestvars.cpp + hiostream.cpp + httprespheaders.cpp + ntwkiolinkpool.cpp + l4handler.cpp ) add_library(http STATIC ${http_STAT_SRCS}) diff --git a/src/http/Makefile.am b/src/http/Makefile.am index f581da494..08d21d6c7 100755 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -15,9 +15,12 @@ denieddir.cpp httpserverconfig.cpp httpextconnector.cpp statusurlmap.cpp context httpsignals.cpp handlertype.cpp handlerfactory.cpp httputil.cpp staticfilecachedata.cpp staticfilecache.cpp \ cacheelement.cpp httpcache.cpp chunkoutputstream.cpp chunkinputstream.cpp httplog.cpp httpmime.cpp \ staticfiledata.cpp httpcontext.cpp httpserverversion.cpp vhostmap.cpp eventdispatcher.cpp staticfilehandler.cpp \ -reqhandler.cpp httpvhost.cpp httpresourcemanager.cpp httpiolink.cpp httpmethod.cpp httpver.cpp \ +reqhandler.cpp httpvhost.cpp httpresourcemanager.cpp ntwkiolink.cpp httpmethod.cpp httpver.cpp \ httpstatuscode.cpp httpstatusline.cpp httpheader.cpp smartsettings.cpp datetime.cpp \ -httplistener.cpp httpresp.cpp httpreq.cpp httpconnection.cpp moov.cpp iptogeo.cpp +httplistener.cpp httpresp.cpp httpreq.cpp httpconnection.cpp moov.cpp iptogeo.cpp \ +hiostream.cpp httprespheaders.cpp ntwkiolinkpool.cpp l4handler.cpp + + ####### kdevelop will overwrite this part!!! (end)############ diff --git a/src/http/Makefile.in b/src/http/Makefile.in index 36cda5263..e5914d4e1 100644 --- a/src/http/Makefile.in +++ b/src/http/Makefile.in @@ -95,12 +95,14 @@ am_libhttp_a_OBJECTS = moduserdir.$(OBJEXT) contextnode.$(OBJEXT) \ vhostmap.$(OBJEXT) eventdispatcher.$(OBJEXT) \ staticfilehandler.$(OBJEXT) reqhandler.$(OBJEXT) \ httpvhost.$(OBJEXT) httpresourcemanager.$(OBJEXT) \ - httpiolink.$(OBJEXT) httpmethod.$(OBJEXT) httpver.$(OBJEXT) \ + ntwkiolink.$(OBJEXT) httpmethod.$(OBJEXT) httpver.$(OBJEXT) \ httpstatuscode.$(OBJEXT) httpstatusline.$(OBJEXT) \ httpheader.$(OBJEXT) smartsettings.$(OBJEXT) \ datetime.$(OBJEXT) httplistener.$(OBJEXT) httpresp.$(OBJEXT) \ httpreq.$(OBJEXT) httpconnection.$(OBJEXT) moov.$(OBJEXT) \ - iptogeo.$(OBJEXT) + iptogeo.$(OBJEXT) hiostream.$(OBJEXT) \ + httprespheaders.$(OBJEXT) ntwkiolinkpool.$(OBJEXT) \ + l4handler.$(OBJEXT) libhttp_a_OBJECTS = $(am_libhttp_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -245,9 +247,10 @@ denieddir.cpp httpserverconfig.cpp httpextconnector.cpp statusurlmap.cpp context httpsignals.cpp handlertype.cpp handlerfactory.cpp httputil.cpp staticfilecachedata.cpp staticfilecache.cpp \ cacheelement.cpp httpcache.cpp chunkoutputstream.cpp chunkinputstream.cpp httplog.cpp httpmime.cpp \ staticfiledata.cpp httpcontext.cpp httpserverversion.cpp vhostmap.cpp eventdispatcher.cpp staticfilehandler.cpp \ -reqhandler.cpp httpvhost.cpp httpresourcemanager.cpp httpiolink.cpp httpmethod.cpp httpver.cpp \ +reqhandler.cpp httpvhost.cpp httpresourcemanager.cpp ntwkiolink.cpp httpmethod.cpp httpver.cpp \ httpstatuscode.cpp httpstatusline.cpp httpheader.cpp smartsettings.cpp datetime.cpp \ -httplistener.cpp httpresp.cpp httpreq.cpp httpconnection.cpp moov.cpp iptogeo.cpp +httplistener.cpp httpresp.cpp httpreq.cpp httpconnection.cpp moov.cpp iptogeo.cpp \ +hiostream.cpp httprespheaders.cpp ntwkiolinkpool.cpp l4handler.cpp ####### kdevelop will overwrite this part!!! (end)############ @@ -320,6 +323,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expiresctrl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlerfactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlertype.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hiostream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hotlinkctrl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htauth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htpasswd.Po@am__quote@ @@ -332,7 +336,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpglobals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httphandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpheader.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpiolink.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httplistener.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httplistenerlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httplog.Po@am__quote@ @@ -343,6 +346,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpreq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpresourcemanager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpresp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httprespheaders.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpserverconfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpserverversion.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpsignals.Po@am__quote@ @@ -353,8 +357,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpvhost.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpvhostlist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iptogeo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/l4handler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moduserdir.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/moov.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntwkiolink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntwkiolinkpool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/phpconfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipeappender.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reqhandler.Po@am__quote@ diff --git a/src/http/accesslog.cpp b/src/http/accesslog.cpp index ebe034170..e7dab5777 100644 --- a/src/http/accesslog.cpp +++ b/src/http/accesslog.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -304,16 +303,16 @@ void AccessLog::customLog( HttpConnection* pConn ) } break; case REF_CONN_STATE: - if ( pConn->isConnCanceled() ) + if ( pConn->getStream()->isAborted() ) { m_buf.append( 'X' ); } - else if ( pConn->isClosing() ) + else if ( pConn->getReq()->isKeepAlive() ) { - m_buf.append( '-' ); + m_buf.append( '+' ); } else - m_buf.append( '+' ); + m_buf.append( '-' ); break; case REF_COOKIE_VAL: case REF_ENV: @@ -520,8 +519,8 @@ void AccessLog::log( HttpConnection* pConn ) HttpResp* pResp = pConn->getResp(); const char * pUser = pReq->getAuthUser(); long contentWritten = pResp->getBodySent(); - const ClientInfo * pInfo = pConn->getClientInfo(); - const char * pAddr = pInfo->getHostName(); + char * pAddr; + char achTemp[100]; pResp->needLogAccess( 0 ); if ( m_iPipedLog ) { @@ -534,16 +533,10 @@ void AccessLog::log( HttpConnection* pConn ) if ( m_pCustomFormat ) return customLog( pConn ); - - if (( pAddr )&&( *pAddr )) - { - n = pInfo->getHostNameLen(); - } - else - { - pAddr = pInfo->getAddrString(); - n = pInfo->getAddrStrLen(); - } + + pAddr = achTemp; + n = RequestVars::getReqVar( pConn, REF_REMOTE_HOST, pAddr, sizeof( achTemp ) ); + m_buf.appendNoCheck( pAddr, n ); if ( ! *pUser ) { diff --git a/src/http/clientcache.cpp b/src/http/clientcache.cpp index 63483e106..60e05ea5d 100644 --- a/src/http/clientcache.cpp +++ b/src/http/clientcache.cpp @@ -27,7 +27,6 @@ #include #include #include - #include #include diff --git a/src/http/contextnode.cpp b/src/http/contextnode.cpp index 34ef82b22..0d6d37273 100644 --- a/src/http/contextnode.cpp +++ b/src/http/contextnode.cpp @@ -59,10 +59,12 @@ void ContextNode::setContextUpdateParent( HttpContext* pContext, int noRedirect pOldParent = getParentContext(); setChildrenParentContext( pOldParent, pNewParent, noRedirect ); if ( pContext ) + { if ( m_pContext ) pContext->setParent( m_pContext->getParent() ); else pContext->setParent( getParentContext() ); + } m_pContext = pContext; } diff --git a/src/http/eventdispatcher.cpp b/src/http/eventdispatcher.cpp index 145bdd972..27897385c 100644 --- a/src/http/eventdispatcher.cpp +++ b/src/http/eventdispatcher.cpp @@ -184,7 +184,7 @@ static inline void processTimerNew() gettimeofday( &tv, NULL ); //FIXME: debug code - int n = tv.tv_usec / ( 1000000 / TIMER_PRECISION ); + //int n = tv.tv_usec / ( 1000000 / TIMER_PRECISION ); DateTime::s_curTime = tv.tv_sec; DateTime::s_curTimeMS = tv.tv_usec; @@ -193,7 +193,13 @@ static inline void processTimerNew() if ( HttpGlobals::s_tmToken != HttpGlobals::s_tmPrevToken ) { if ( HttpGlobals::s_tmToken < HttpGlobals::s_tmPrevToken ) + { + if ( getppid() == 1 ) + { + HttpSignals::setSigStop(); + } HttpServer::getInstance().onTimer(); + } HttpGlobals::getMultiplexer()->timerExecute(); HttpGlobals::getConnLimitCtrl()->checkWaterMark(); //LOG_D(( "processTimer()" )); diff --git a/src/http/hiostream.cpp b/src/http/hiostream.cpp new file mode 100644 index 000000000..312af3ad0 --- /dev/null +++ b/src/http/hiostream.cpp @@ -0,0 +1,33 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#include "hiostream.h" + + +HioStream::~HioStream() +{ + +} + + + +HioStreamHandler::~HioStreamHandler() +{ + +} + diff --git a/src/http/hiostream.h b/src/http/hiostream.h new file mode 100644 index 000000000..8cb7443cc --- /dev/null +++ b/src/http/hiostream.h @@ -0,0 +1,165 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef HIOSTREAM_H +#define HIOSTREAM_H + +#include +#include +#include +#include + +class IOVec; + +class HioStreamHandler; + +enum HioState +{ + HIOS_DISCONNECTED, + HIOS_CONNECTED, + HIOS_CLOSING, + HIOS_SHUTDOWN, +}; + +enum HiosProtocol +{ + HIOS_PROTO_HTTP = 0, + HIOS_PROTO_SPDY2 = 1, + HIOS_PROTO_SPDY3 = 2 +}; + +#define HIO_FLAG_PEER_SHUTDOWN (1<<0) +#define HIO_FLAG_LOCAL_SHUTDOWN (1<<1) +#define HIO_FLAG_WANT_READ (1<<2) +#define HIO_FLAG_WANT_WRITE (1<<3) +#define HIO_FLAG_ABORT (1<<4) +#define HIO_FLAG_PEER_RESET (1<<5) +#define HIO_FLAG_HANDLER_RELEASE (1<<6) +#define HIO_FLAG_BUFF_FULL (1<<7) +#define HIO_FLAG_FLOWCTRL (1<<8) + +class HioStream : public InputStream, public OutputStream, public LogTracker +{ + HioStreamHandler * m_pHandler; + off_t m_lBytesRecv; + off_t m_lBytesSent; + char m_iState; + char m_iProtocol; + short m_iFlag; + +public: + HioStream() + : m_pHandler( NULL ) + , m_lBytesRecv( 0 ) + , m_lBytesSent( 0 ) + , m_iState( HIOS_DISCONNECTED ) + , m_iProtocol( HIOS_PROTO_HTTP ) + , m_iFlag( 0 ) + {} + virtual ~HioStream(); + + virtual int sendfile( IOVec &vector, int &total, int fdSrc, off_t off, size_t size ) = 0; + virtual int readv( struct iovec *vector, size_t count ) + { return -1; } + + virtual int sendHeaders( IOVec &vector, int headerCount ) = 0; + + virtual void suspendRead() = 0; + virtual void continueRead() = 0; + virtual void suspendWrite() = 0; + virtual void continueWrite() = 0; + virtual void switchWriteToRead() = 0; + virtual void onTimer() = 0; + //virtual uint32_t GetStreamID() = 0; + + void reset() + { memset( &m_pHandler, 0, (char*)(&m_iFlag+1) - (char *)&m_pHandler ); } + + HioStreamHandler * getHandler() const { return m_pHandler; } + void setHandler( HioStreamHandler * p ) { m_pHandler = p; } + + short isWantRead() const { return m_iFlag & HIO_FLAG_WANT_READ; } + short isWantWrite() const { return m_iFlag & HIO_FLAG_WANT_WRITE; } + short isReadyToRelease() const { return m_iFlag & HIO_FLAG_HANDLER_RELEASE; } + + void setFlag( int flagbit, int val ) + { m_iFlag = (val)? ( m_iFlag | flagbit ):( m_iFlag & ~flagbit ); } + short getFlag( int flagbit ) const { return flagbit & m_iFlag; } + + short isAborted() const { return m_iFlag & HIO_FLAG_ABORT; } + void setAbortedFlag() { m_iFlag |= HIO_FLAG_ABORT; } + + void handlerReadyToRelease(){ m_iFlag |= HIO_FLAG_HANDLER_RELEASE; } + short canWrite() const { return m_iFlag & HIO_FLAG_BUFF_FULL; } + + char getProtocol() const { return m_iProtocol; } + void setProtocol( int p ) { m_iProtocol = p; } + + int isSpdy() const { return m_iProtocol; } + + short getState() const { return m_iState; } + void setState( HioState st ) { m_iState = st; } + + void bytesRecv( int n ) { m_lBytesRecv += n; } + void bytesSent( int n ) { m_lBytesSent += n; } + + off_t getBytesRecv() const { return m_lBytesRecv; } + off_t getBytesSent() const { return m_lBytesSent; } + + short isPeerShutdown() const { return m_iFlag & HIO_FLAG_PEER_SHUTDOWN; } + +private: + HioStream(const HioStream& other); + HioStream& operator=(const HioStream& other); + bool operator==(const HioStream& other) const; + +}; + +class HioStreamHandler +{ + HioStream * m_pStream; + +public: + HioStreamHandler() + : m_pStream( NULL ) + {} + virtual ~HioStreamHandler(); + + HioStream * getStream() const { return m_pStream; } + void setStream( HioStream * p ) { m_pStream = p; } + void assignStream( HioStream * p ) + { + m_pStream = p; + p->setHandler( this ); + } + + virtual int onInitConnected() = 0; + virtual int onReadEx() = 0; + virtual int onWriteEx() = 0; + virtual int onCloseEx() = 0; + virtual int onTimerEx() = 0; + + virtual void recycle() = 0; + +private: + HioStreamHandler(const HioStreamHandler& other); + HioStreamHandler& operator=(const HioStreamHandler& other); + bool operator==(const HioStreamHandler& other) const; +}; + + +#endif // HIOSTREAM_H diff --git a/src/http/htauth.cpp b/src/http/htauth.cpp index 498e58b6c..e10c31c36 100644 --- a/src/http/htauth.cpp +++ b/src/http/htauth.cpp @@ -36,7 +36,7 @@ #include #include #include - +#include "http/httprespheaders.h" HTAuth::HTAuth() : m_pName( NULL ) @@ -86,33 +86,26 @@ int HTAuth::buildWWWAuthHeader( const char * pName ) if ( m_authHeader ) { m_authHeaderLen = safe_snprintf( m_authHeader, len, - "WWW-Authenticate: Basic realm=\"%s\"\r\n", pName ); + "Basic realm=\"%s\"", pName ); return 0; } } return -1; } -int HTAuth::addWWWAuthHeader( AutoBuf &buf ) const +int HTAuth::addWWWAuthHeader( HttpRespHeaders &buf ) const { if ( m_iAuthType & AUTH_BASIC ) - { - buf.append( m_authHeader, m_authHeaderLen); - return 0; - } + buf.add(-1, "WWW-Authenticate", 16, m_authHeader, m_authHeaderLen); else if ( m_iAuthType & AUTH_DIGEST ) { - if ( buf.available() < 256 ) - if ( buf.grow( 256 ) == -1 ) - return -1; - //FIXME: add digest header - int iBufLen = safe_snprintf( buf.end(), buf.available(), - "WWW-Authenticate: Digest realm=\"%s\" nonce=\"%lu\"\r\n", + char sTemp[256] = {0}; + int n = safe_snprintf( sTemp, 255, "Digest realm=\"%s\" nonce=\"%lu\"\r\n", m_authHeader, time(NULL) ); - buf.used( iBufLen ); - return 0; + + buf.add(-1, "WWW-Authenticate", 16, sTemp, n); } - return -1; + return 0; } #define MAX_PASSWD_LEN 128 @@ -179,13 +172,9 @@ int HTAuth::digestAuth( HttpConnection * pConn, const char * pAuthorization, const char * username = NULL; int username_len; const char * realm = NULL; - int realm_len; const char * nonce = NULL; - int nonce_len; const char * requri = NULL; - int requri_len; const char * resp_digest = NULL; - int resp_digest_len; const char * p = pAuthorization; const char * pEnd = p + size; const char * pNameEnd; @@ -237,23 +226,18 @@ int HTAuth::digestAuth( HttpConnection * pConn, const char * pAuthorization, else if ( strncasecmp( pNameBegin, "realm", 5 ) == 0 ) { realm = pValueBegin; - realm_len = pValueEnd - pValueBegin; } else if ( strncasecmp( pNameBegin, "nonce", 5 ) == 0 ) { nonce = pValueBegin; - nonce_len = pValueEnd - pValueBegin; - } else if ( strncasecmp( pNameBegin, "uri", 3 ) == 0 ) { requri = pValueBegin; - requri_len = pValueEnd - pValueBegin; } else if ( strncasecmp( pNameBegin, "response", 8 ) == 0 ) { resp_digest = pValueBegin; - resp_digest_len = pValueEnd - pValueBegin; } else if ( strncasecmp( pNameBegin, "nc", 2 ) == 0 ) { diff --git a/src/http/htauth.h b/src/http/htauth.h index 71753f170..928866817 100644 --- a/src/http/htauth.h +++ b/src/http/htauth.h @@ -28,6 +28,7 @@ class AutoBuf; class HttpConnection; class StringList; class UserDir; +class HttpRespHeaders; class HTAuth { @@ -63,7 +64,7 @@ class HTAuth const UserDir* getUserDir() const { return m_pUserDir; } //const AuthUser * getUser( const char * pUser, int userLen ) const; - int addWWWAuthHeader( AutoBuf& buf ) const ; + int addWWWAuthHeader( HttpRespHeaders& buf ) const ; int basicAuth( HttpConnection * pConn, const char * pAuthorization, int headerLen, char * pAuthUser, int bufLen, const AuthRequired * pRequired ) const; diff --git a/src/http/httpcgitool.cpp b/src/http/httpcgitool.cpp index 8ece12828..18909a3e3 100644 --- a/src/http/httpcgitool.cpp +++ b/src/http/httpcgitool.cpp @@ -118,14 +118,12 @@ int HttpCgiTool::processHeaderLine( HttpExtConnector * pExtConn, const char * pL if ( strncmp( p, "charset=", 8 ) == 0 ) break; } - AutoBuf& buf = pResp->getOutputBuf(); - if ( buf.available() < pLineEnd - pLineBegin + pCharset->len() + 4 ) - { - buf.grow( pLineEnd - pLineBegin + pCharset->len() + 4 ); - } - buf.appendNoCheck( pLineBegin, pLineEnd - pLineBegin ); - buf.appendNoCheck( pCharset->c_str(), pCharset->len() ); - buf.appendNoCheck( "\r\n", 2 ); + HttpRespHeaders& buf = pResp->getHeaders(); + AutoStr2 str = ""; + str.append( pLineBegin, pLineEnd - pLineBegin ); + str.append( pCharset->c_str(), pCharset->len() ); + str.append( "\r\n", 2 ); + buf.addNoCheckExptSpdy(str.c_str(), str.len()); } return 0; case HttpHeader::H_CONTENT_ENCODING: @@ -197,7 +195,8 @@ int HttpCgiTool::processHeaderLine( HttpExtConnector * pExtConn, const char * pL } return 0; } - return pResp->appendHeaderLine( pLineBegin, pLineEnd ); + assert( pKeyEnd ); + return pResp->appendHeader( pLineBegin, pKeyEnd - pLineBegin, pValue, pLineEnd - pValue ); } int HttpCgiTool::parseRespHeader( HttpExtConnector * pExtConn, @@ -618,22 +617,14 @@ int HttpCgiTool::processContentType( HttpReq * pReq, HttpResp* pResp, if ( strncmp( p, "charset=", 8 ) == 0 ) break; } - AutoBuf& buf = pResp->getOutputBuf(); - if ( buf.available() < valLen + pCharset->len() + 18 ) - { - buf.grow( valLen + pCharset->len() + 18 ); - } - buf.appendNoCheck( "Content-Type: ", 14 ); - int offset = buf.size(); - buf.appendNoCheck( pValue, valLen ); - buf.appendNoCheck( pCharset->c_str(), pCharset->len() ); - buf.appendNoCheck( "\r\n", 2 ); - pResp->setContentTypeHeaderInfo( offset, buf.size() - 2 - offset ); + HttpRespHeaders& buf = pResp->getHeaders(); + buf.add(HttpHeader::H_CONTENT_TYPE, "Content-Type", 12, pValue, valLen); + buf.appendLastVal( "Content-Type", 12, pCharset->c_str(), pCharset->len() ); } return 0; } while( 0 ); - pResp->setContentTypeHeaderInfo( pResp->getOutputBuf().size() + 14, valLen ); + return pResp->appendHeader( "Content-Type", 12, pValue, valLen ); } diff --git a/src/http/httpconnection.cpp b/src/http/httpconnection.cpp index a7b1e6785..631e2476f 100644 --- a/src/http/httpconnection.cpp +++ b/src/http/httpconnection.cpp @@ -16,18 +16,29 @@ * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include - #include #include +#include #include -#include #include -#include +#include #include +#include #include #include #include @@ -36,43 +47,31 @@ #include #include #include +#include #include #include #include -#include -#include - #include #include +#include +#include #include #include #include - #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include +#include - -#include +#include "http/l4handler.h" +#include "extensions/l4conn.h" HttpConnection::HttpConnection() { ::memset( &m_pChunkIS, 0, (char *)(&m_iReqServed + 1) - (char *)&m_pChunkIS ); - m_logID.resizeBuf( MAX_LOGID_LEN + 1 ); - m_logID.buf()[MAX_LOGID_LEN] = 0; - m_request.setILog( this ); + m_pNtwkIOLink = NULL; + m_iState = HCS_WAITING; } HttpConnection::~HttpConnection() @@ -83,22 +82,28 @@ int HttpConnection::onInitConnected() { m_lReqTime = DateTime::s_curTime; m_iReqTimeMs = DateTime::s_curTimeMS; - m_response.setSSL( isSSL() ); + if ( m_pNtwkIOLink ) + { + m_response.setSSL( m_pNtwkIOLink->isSSL() ); + setVHostMap( m_pNtwkIOLink->getVHostMap() ); + } + setState( HCS_READING ); + getStream()->setFlag( HIO_FLAG_WANT_READ, 1 ); + m_request.setILog( getStream() ); return 0; } + +/* const char * HttpConnection::buildLogId() { - AutoStr2 & id = m_logID; -// int n = len + 32; -// if ( !id.resizeBuf( n ) ) -// return; + AutoStr2 & id = getStream()->getIdBuf(); int len ; char * p = id.buf(); char * pEnd = p + MAX_LOGID_LEN; - len = safe_snprintf( id.buf(), MAX_LOGID_LEN, "%s:%hu-", - getPeerAddrString(), m_iRemotePort ); + len = safe_snprintf( id.buf(), MAX_LOGID_LEN, "%s-", + getStream()->getLogId() ); id.setLen( len ); p += len; len = safe_snprintf( p, pEnd - p, "%hu", m_iReqServed ); @@ -108,9 +113,9 @@ const char * HttpConnection::buildLogId() { safe_snprintf( p, pEnd - p, "#%s", pVHost->getName() ); } - m_iLogIdBuilt = 1; return id.c_str(); } +*/ #include #include @@ -135,8 +140,9 @@ void HttpConnection::logAccess( int cancelled ) else m_response.needLogAccess( 0 ); } - else - HttpLog::logAccess( NULL, 0, this ); + else + if ( m_pNtwkIOLink ) + HttpLog::logAccess( NULL, 0, this ); } @@ -146,8 +152,7 @@ void HttpConnection::nextRequest() if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] HttpConnection::nextRequest()!", getLogId() )); - if ( isSSL() ) - getSSL()->flush(); + getStream()->flush(); if ( m_pHandler ) { HttpGlobals::s_reqStats.incReqProcessed(); @@ -175,13 +180,7 @@ void HttpConnection::nextRequest() if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] Non-KeepAlive, CLOSING!", getLogId() )); - if ( !inProcess() ) - closeConnection(); - else - setState( HC_CLOSING ); - //setState( HC_CLOSING ); - //if ( !inProcess() ) - // continueWrite(); + closeConnection(); } else { @@ -189,14 +188,14 @@ void HttpConnection::nextRequest() ++m_iReqServed; m_lReqTime = DateTime::s_curTime; m_iReqTimeMs = DateTime::s_curTimeMS; - switchWriteToRead(); - if ( m_iLogIdBuilt ) + getStream()->switchWriteToRead(); + if ( getStream()->isLogIdBuilt() ) { - safe_snprintf( m_logID.buf() + - m_logID.len(), 10, "%hu", m_iReqServed ); + safe_snprintf( getStream()->getIdBuf().buf() + + getStream()->getIdBuf().len(), 10, "%hu", m_iReqServed ); } m_request.reset2(); - if ( m_pRespCache ) + if ( m_pRespBodyBuf ) releaseRespCache(); if ( m_pGzipBuf ) releaseGzipBuf(); @@ -205,14 +204,13 @@ void HttpConnection::nextRequest() if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] Pending data in header buffer, set state to READING!", getLogId() )); - setState( HC_READING ); - setActiveTime( m_lReqTime ); + setState( HCS_READING ); //if ( !inProcess() ) processPending( 0 ); } else { - setState( HC_WAITING ); + setState( HCS_WAITING ); ++HttpGlobals::s_iIdleConns; } } @@ -230,7 +228,7 @@ int HttpConnection::read( char * pBuf, int size ) m_request.pendingDataProcessed( len ); return len; } - return HttpIOLink::read( pBuf, size ); + return getStream()->read( pBuf, size ); } int HttpConnection::readv( struct iovec *vector, size_t count) @@ -266,7 +264,7 @@ int HttpConnection::processReqBody() int ret = m_request.prepareReqBodyBuf(); if ( ret ) return ret; - setState( HC_READING_BODY ); + setState( HCS_READING_BODY ); if ( m_request.isChunked() ) { setupChunkIS(); @@ -281,7 +279,7 @@ void HttpConnection::setupChunkIS() assert ( m_pChunkIS == NULL ); { m_pChunkIS = HttpGlobals::getResManager()->getChunkInputStream(); - m_pChunkIS->setStream( this ); + m_pChunkIS->setStream( getStream() ); m_pChunkIS->open(); } } @@ -367,7 +365,7 @@ int HttpConnection::readReqBody() m_pChunkIS = NULL; m_request.tranEncodeToContentLen(); } - //suspendRead(); + suspendRead(); ret = processURI( 0 ); return ret; @@ -385,7 +383,7 @@ int HttpConnection::readReqBody( char * pBuf, int size ) int toRead = m_request.getBodyRemain(); if ( toRead > size ) toRead = size ; - len = HttpIOLink::read( pBuf, toRead ); + len = getStream()->read( pBuf, toRead ); } return len; } @@ -406,7 +404,7 @@ int HttpConnection::readToHeaderBuf() if ( avail > 2048 ) avail = 2048; char * pBuf = headerBuf.end(); - sz = HttpIOLink::read( pBuf, + sz = getStream()->read( pBuf, avail ); if ( sz > 0 ) { @@ -457,7 +455,7 @@ int HttpConnection::readToHeaderBuf() void HttpConnection::processPending( int ret ) { - if (( getState() != HC_READING )|| + if (( getState() != HCS_READING )|| ( m_request.pendingHeaderDataLen() < 2 )) return; if ( D_ENABLED( DL_LESS )) @@ -469,22 +467,76 @@ void HttpConnection::processPending( int ret ) } ret = m_request.processHeader(); if ( ret == 1 ) + { if ( isSSL() ) ret = readToHeaderBuf(); else return; + } if (( !ret )&&( m_request.getStatus() == HttpReq::HEADER_OK )) ret = processNewReq(); - if (( ret )&&( getState() < HC_SHUTDOWN )) + if (( ret )&&( getStream()->getState() < HIOS_SHUTDOWN )) { httpError( ret ); } } +int HttpConnection::updateClientInfoFromProxyHeader( const char * pProxyHeader ) +{ + char achIP[128]; + int len = m_request.getHeaderLen( HttpHeader::H_X_FORWARDED_FOR ); + char * p = (char *)memchr( pProxyHeader, ',', len ); + if ( p ) + len = p - pProxyHeader; + if (( len <= 0 )||( len > 16 )) + { + //error, not a valid IPv4 address + return 0; + } + + memmove( achIP, pProxyHeader, len ); + achIP[len] = 0; + struct sockaddr_in addr; + memset( &addr, 0, sizeof( sockaddr_in ) ); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr( achIP ); + if ( addr.sin_addr.s_addr == INADDR_BROADCAST ) + { + //Failed to parse the address string to IPv4 address + return 0; + } + ClientInfo * pInfo = HttpGlobals::getClientCache() + ->getClientInfo( (struct sockaddr *)&addr ); + if ( pInfo ) + { + if ( pInfo->checkAccess() ) + { + //Access is denied + return SC_403; + } + } + m_request.addEnv( "PROXY_REMOTE_ADDR", 17, + getPeerAddrString(), getPeerAddrStrLen() ); + + m_pNtwkIOLink->changeClientInfo( pInfo ); + return 0; +} int HttpConnection::processNewReq() { + int ret; + if ((HttpGlobals::s_useProxyHeader == 1)|| + ((HttpGlobals::s_useProxyHeader == 2)&&( getClientInfo()->getAccess() == AC_TRUST ))) + { + const char * pProxyHeader = m_request.getHeader( HttpHeader::H_X_FORWARDED_FOR ); + if ( *pProxyHeader ) + { + ret = updateClientInfoFromProxyHeader( pProxyHeader ); + if ( ret ) + return ret; + } + } m_lReqTime = DateTime::s_curTime; m_iReqTimeMs = DateTime::s_curTimeMS; m_response.needLogAccess(1); @@ -502,25 +554,45 @@ int HttpConnection::processNewReq() } return SC_404; } - setLogger( pVHost->getLogger() ); - if ( m_iLogIdBuilt ) + getStream()->setLogger( pVHost->getLogger() ); + if ( getStream()->isLogIdBuilt() ) { - AutoStr2 &id = m_logID; - register char * p = id.buf() + id.len() + 1; + AutoStr2 &id = getStream()->getIdBuf(); + register char * p = id.buf() + id.len(); while( *p && *p != '#' ) ++p; *p++ = '#'; memccpy( p, pVHost->getName(), 0, id.buf() + MAX_LOGID_LEN - p ); } - int ret = m_request.processNewReqData(getPeerAddr()); + ret = m_request.processNewReqData(getPeerAddr()); if ( ret ) { return ret; } - if ((isThrottle())&&( getClientInfo()->getAccess() != AC_TRUST )) - getThrottleCtrl()->adjustLimits( pVHost->getThrottleLimits() ); - if ( m_request.isKeepAlive() ) + + if ( m_request.isWebsocket() ) + { + HttpContext* pContext = pVHost->getContext(m_request.getURI(), 0); + LOG_D ((getLogger(), "[%s] VH: web socket, name: [%s] URI: [%s]", getLogId(), pVHost->getName(), m_request.getURI() )); + const char tmp[sizeof(GSockAddr) + 1] = {0}; + if ( pContext && memcmp((char*)pContext->getGSockAddr(), tmp, sizeof(GSockAddr)) != 0 ) + { + L4Handler *pL4Handler = new L4Handler(); + pL4Handler->assignStream(this->m_pNtwkIOLink); + pL4Handler->init(m_request, pContext->getGSockAddr()); + LOG_D ((getLogger(), "[%s] VH: %s web socket !!!", getLogId(), pVHost->getName() )); + return 0; + //DO NOT release pL4Handler, it will be releaseed itself. + } + } + + + if ((m_pNtwkIOLink->isThrottle())&&( m_pNtwkIOLink->getClientInfo()->getAccess() != AC_TRUST )) + m_pNtwkIOLink->getThrottleCtrl()->adjustLimits( pVHost->getThrottleLimits() ); + if ( getStream()->isSpdy() ) + m_request.keepAlive( 0 ); + else if ( m_request.isKeepAlive() ) { if ( m_iReqServed >= pVHost->getMaxKAReqs() ) { @@ -539,7 +611,7 @@ int HttpConnection::processNewReq() ", keep-alive off.", getLogId())); } - else if ( getClientInfo()->getOverLimitTime() ) + else if ( m_pNtwkIOLink->getClientInfo()->getOverLimitTime() ) { m_request.keepAlive( false ); if ( D_ENABLED( DL_LESS ) ) @@ -564,7 +636,7 @@ int HttpConnection::processNewReq() } else { - //suspendRead(); + suspendRead(); return processURI( 0 ); } } @@ -625,7 +697,7 @@ int HttpConnection::checkAuthorizer( const HttpHandler * pHandler ) int ret = assignHandler( pHandler ); if ( ret ) return ret; - setState( HC_EXT_AUTH ); + setState( HCS_EXT_AUTH ); return m_pHandler->process( this, pHandler ); } @@ -657,8 +729,6 @@ int HttpConnection::processURI( int resume ) const HttpVHost * pVHost = m_request.getVHost(); int ret; int proceed = 1; - int isCached = 0; - const HttpContext * pContext; if ( !resume ) { //virtual host level URL rewrite @@ -670,8 +740,6 @@ int HttpConnection::processURI( int resume ) ret = HttpGlobals::s_RewriteEngine. processRuleSet( pVHost->getRootContext().getRewriteRules(), this, NULL, NULL ); - if ( getState() == HC_CLOSING ) - return 0; if ( ret == -3 ) //rewrite happens { @@ -794,7 +862,7 @@ int HttpConnection::processURI( int resume ) getLogId(), ret1)); if ( ret1 == -1 ) //processing authentication { - setState(HC_EXT_AUTH ); + setState(HCS_EXT_AUTH ); return 0; } return ret1; @@ -821,7 +889,7 @@ int HttpConnection::processURI( int resume ) case 0: //ok return handlerProcess( m_request.getHttpHandler() ); case -1: //processing authentication - setState(HC_EXT_AUTH ); + setState(HCS_EXT_AUTH ); return 0; default: //error return ret; @@ -877,8 +945,7 @@ int HttpConnection::getParsedScript( SSIScript * &pScript ) int HttpConnection::startServerParsed() { SSIScript * pScript = NULL; - int ret; - ret = getParsedScript( pScript ); + getParsedScript( pScript ); if ( !pScript ) return SC_500; @@ -940,7 +1007,7 @@ int HttpConnection::handlerProcess( const HttpHandler * pHandler ) int ret = assignHandler(m_request.getHttpHandler() ); if ( ret ) return ret; - setState( HC_PROCESSING ); + setState( HCS_PROCESSING ); //PORT_FIXME: turn off for now //pTC->incReqProcessed( m_pHandler->getType() == HandlerType::HT_DYNAMIC ); @@ -1007,7 +1074,7 @@ int HttpConnection::assignHandler( const HttpHandler * pHandler ) } else { - m_response.reset(); + resetResp(); } const char * pType = HandlerType::getHandlerTypeString( handlerType ); @@ -1018,10 +1085,10 @@ int HttpConnection::assignHandler( const HttpHandler * pHandler ) getLogId(), pType )); } - if ( m_iLogIdBuilt ) + if ( getStream()->isLogIdBuilt() ) { - AutoStr2 &id = m_logID; - register char * p = id.buf() + id.len() + 1; + AutoStr2 &id = getStream()->getIdBuf(); + register char * p = id.buf() + id.len(); while( *p && *p != ':' ) ++p; @@ -1044,13 +1111,27 @@ int HttpConnection::assignHandler( const HttpHandler * pHandler ) } +int HttpConnection::sendSpdyHeaders() +{ + if ( m_response.getHeaderLeft() ) + { + getStream()->sendHeaders( m_response.getIov(), m_response.getHeaders().getTotalCount() ); + m_response.getIov().clear(); + m_response.setHeaderLeft( 0 ); + } + return 0; +} + int HttpConnection::beginWrite() { //int nodelay = 0; //::setsockopt( getfd(), IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof( int ) ); - setState( HC_WRITING ); + setState( HCS_WRITING ); + if (getStream()->isSpdy() ) + sendSpdyHeaders(); + if (( sendBody() )||(m_response.getBodySent() < 0 )) { return doWrite(); @@ -1081,7 +1162,7 @@ void HttpConnection::sendHttpError( const char * pAdditional ) SSIEngine::printError( this, NULL ); } continueWrite(); - setState( HC_COMPLETE ); + setState( HCS_COMPLETE ); return; } if ( (m_request.getStatus() != HttpReq::HEADER_OK ) @@ -1089,7 +1170,6 @@ void HttpConnection::sendHttpError( const char * pAdditional ) || m_request.getBodyRemain() > 0 ) { m_request.keepAlive( false ); - setPeerShutdown( IO_HTTP_ERR ); } // Let HEAD request follow the errordoc URL, the status code could be changed //if ( sendBody() ) @@ -1148,7 +1228,7 @@ void HttpConnection::sendHttpError( const char * pAdditional ) } */ } - setState( HC_WRITING ); + setState( HCS_WRITING ); buildErrorResponse( pAdditional ); writeComplete(); HttpGlobals::s_reqStats.incReqProcessed(); @@ -1174,7 +1254,7 @@ int HttpConnection::buildErrorResponse( const char * errMsg ) return 0; } - m_response.reset(); + resetResp(); m_response.prepareHeaders( &m_request ); //register int errCode = m_request.getStatusCode(); register unsigned int ver = m_request.getVersion(); @@ -1190,19 +1270,24 @@ int HttpConnection::buildErrorResponse( const char * errMsg ) } if ( sendBody() ) { - const char * pHtml = HttpStatusCode::getHtml( errCode ); + const char * pHtml = HttpStatusCode::getRealHtml( errCode ); if ( pHtml ) { int len = HttpStatusCode::getBodyLen( errCode ); m_response.setContentLen( len ); - m_response.safeAppend( pHtml, HttpStatusCode::getTotalLen( errCode )); + m_response.iovAppend( HttpStatusCode::getHeaders( errCode ), HttpStatusCode::getHeadersLen( errCode )); m_response.finalizeHeader( ver, errCode); + if ( getStream()->isSpdy() ) + sendSpdyHeaders(); + m_response.getIov().append( pHtml, len ); m_response.written( len ); + m_response.setHeaderLeft( len ); return 0; } } - m_response.endHeader(); m_response.finalizeHeader( ver, errCode); + if ( getStream()->isSpdy() ) + sendSpdyHeaders(); return 0; } @@ -1218,12 +1303,11 @@ int HttpConnection::onReadEx() int ret = 0; switch( getState() ) { - case HC_WAITING: - setActiveTime( DateTime::s_curTime ); + case HCS_WAITING: --HttpGlobals::s_iIdleConns; - setState( HC_READING ); - //fall through; - case HC_READING: + setState( HCS_READING ); + //fall through; + case HCS_READING: ret = readToHeaderBuf(); if ( D_ENABLED( DL_LESS )) { @@ -1243,14 +1327,14 @@ int HttpConnection::onReadEx() if ( !ret ) return 0; break; - case HC_READING_BODY: + case HCS_READING_BODY: ret = readReqBody(); break; default: suspendRead(); return 0; } - if (( ret )&&( getState() < HC_SHUTDOWN )) + if (( ret )&&( getStream()->getState() < HIOS_SHUTDOWN )) { httpError( ret ); } @@ -1285,7 +1369,7 @@ int HttpConnection::flush() { IOVec & iov = m_response.getIov(); int total = m_response.getHeaderLeft(); - int written = HttpIOLink::writev( iov, total ); + int written = getStream()->writev( iov, total ); if ( written >= total ) { m_response.setHeaderLeft( 0 ); @@ -1301,11 +1385,7 @@ int HttpConnection::flush() } } } - if ( isSSL() ) - { - return flushSSL(); - } - return 0; + return getStream()->flush(); } void HttpConnection::writeComplete() @@ -1314,14 +1394,15 @@ void HttpConnection::writeComplete() { if ( m_pChunkOS ) { - m_pChunkOS->close( m_response.getIov(), - m_response.getHeaderLeft() ); + if ( getStream()->isSpdy() ) + sendSpdyHeaders(); + m_pChunkOS->close( m_response.getIov(), m_response.getHeaderLeft() ); m_response.setHeaderLeft( 0 ); } } if ( flush() == 0 ) { - if ( getState() == HC_WRITING ) + if ( getState() == HCS_WRITING ) { nextRequest(); } @@ -1329,7 +1410,7 @@ void HttpConnection::writeComplete() else { continueWrite(); - setState( HC_COMPLETE ); + setState( HCS_COMPLETE ); } } @@ -1352,10 +1433,10 @@ int HttpConnection::doWrite(int aioSent ) if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] Handler write error, CLOSING!", getLogId() )); - setState( HC_CLOSING ); + getStream()->setState( HIOS_CLOSING ); } } - else if ( m_pRespCache ) + else if ( m_pRespBodyBuf ) { if ( m_response.getHeaderTotal() ) { @@ -1374,7 +1455,7 @@ int HttpConnection::doWrite(int aioSent ) } else if ( ret == -1 ) { - setState( HC_CLOSING ); + getStream()->setState( HIOS_CLOSING ); } } @@ -1387,30 +1468,28 @@ int HttpConnection::onWriteEx() int ret = 0; switch( getState() ) { - case HC_THROTTLING: - if ( getClientInfo()->getThrottleCtrl().allowProcess(m_pHandler->getType()) ) + case HCS_THROTTLING: + if ( m_pNtwkIOLink->getClientInfo()->getThrottleCtrl().allowProcess(m_pHandler->getType()) ) { - setState( HC_PROCESSING ); - getClientInfo()->getThrottleCtrl().incReqProcessed(m_pHandler->getType()); + setState( HCS_PROCESSING ); + m_pNtwkIOLink->getClientInfo()->getThrottleCtrl().incReqProcessed(m_pHandler->getType()); ret = m_pHandler->process( this, m_request.getHttpHandler() ); - if (( ret )&&( getState() < HC_SHUTDOWN )) + if (( ret )&&( getStream()->getState() < HIOS_SHUTDOWN )) { httpError( ret ); } } break; - case HC_WRITING: + case HCS_WRITING: doWrite(); break; - case HC_COMPLETE: + case HCS_COMPLETE: if ( flush() == 0 ) nextRequest(); return 0; - case HC_CLOSING: - return 0; default: suspendWrite(); - if ( getState() == HC_REDIRECT ) + if ( getState() == HCS_REDIRECT ) { const char * pLocation = m_request.getLocation(); if ( *pLocation ) @@ -1422,7 +1501,7 @@ int HttpConnection::onWriteEx() { SSIEngine::printError( this, NULL ); continueWrite(); - setState( HC_COMPLETE ); + setState( HCS_COMPLETE ); return 0; } m_request.setStatusCode( ret ); @@ -1448,12 +1527,28 @@ void HttpConnection::cleanUpHandler() pHandler->cleanUp( this ); } -void HttpConnection::closeConnection( int cancelled ) + +int HttpConnection::onCloseEx() +{ + closeConnection(); + return 0; +} + + +void HttpConnection::closeConnection( ) { + if ( getStream()->getState() == HIOS_CLOSING ) + getStream()->setState( HIOS_CLOSING ); + if ( getStream()->isReadyToRelease() ) + return; + //FIXME: could be double counted in here. + //if ( getState() == HCS_WAITING ) + // --HttpGlobals::s_iIdleConns; + m_request.keepAlive( 0 ); if ( m_response.shouldLogAccess() ) { - logAccess( cancelled ); + logAccess( getStream()->getFlag( HIO_FLAG_PEER_SHUTDOWN ) ); } if ( m_pHandler ) @@ -1476,7 +1571,7 @@ void HttpConnection::closeConnection( int cancelled ) m_pChunkOS->reset(); releaseChunkOS(); } - if ( m_pRespCache ) + if ( m_pRespBodyBuf ) releaseRespCache(); if ( m_pGzipBuf ) @@ -1487,12 +1582,14 @@ void HttpConnection::closeConnection( int cancelled ) HttpGlobals::getResManager()->recycle( m_pChunkIS ); m_pChunkIS = NULL; } - - close(); + getStream()->handlerReadyToRelease(); + getStream()->close(); } void HttpConnection::recycle() { + if ( D_ENABLED( DL_MORE )) + LOG_D(( getLogger(), "[%s] HttpConnection::recycle()\n", getLogId() )); if ( m_response.shouldLogAccess() ) { LOG_WARN(( "[%s] Request has not been logged into access log, " @@ -1505,16 +1602,18 @@ void HttpConnection::recycle() void HttpConnection::setupChunkOS(int nobuffer) { m_response.setContentLen( -1 ); + if ( !m_request.isKeepAlive() ) + return; if (( m_request.getVersion() == HTTP_1_1 )&&( nobuffer != 2 )) { m_response.appendChunked(); if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] use CHUNKED encoding!", getLogId() )); - if ( m_pChunkOS ) - releaseChunkOS(); - m_pChunkOS = HttpGlobals::getResManager()->getChunkOutputStream(); - m_pChunkOS->setStream( this, &m_response.getIov() ); + if ( m_pChunkOS ) + releaseChunkOS(); + m_pChunkOS = HttpGlobals::getResManager()->getChunkOutputStream(); + m_pChunkOS->setStream( getStream(), &m_response.getIov() ); m_pChunkOS->open(); if ( !nobuffer ) m_pChunkOS->setBuffering( 1 ); @@ -1539,7 +1638,8 @@ void HttpConnection::setBuffering( int s ) int HttpConnection::writeRespBodySendFile( int fdFile, off_t offset, size_t size ) { int& headerTotal = m_response.getHeaderLeft(); - int written = sendfile( m_response.getIov(), headerTotal, + + int written = getStream()->sendfile( m_response.getIov(), headerTotal, fdFile, offset, size ); if ( written > 0 ) m_response.written( written ); @@ -1561,8 +1661,13 @@ int HttpConnection::writeRespBodyPlain( { int written; //printf( "HttpConnection::writeRespBody()!\n" ); + if ( getStream()->isSpdy() ) + { + return getStream()->write( pBuf, size ); + } + iov.append( pBuf, size ); - written = HttpIOLink::writev( iov, headerTotal + size ); + written = getStream()->writev( iov, headerTotal + size ); if ( headerTotal > 0 ) { if ( written >= headerTotal ) @@ -1615,7 +1720,7 @@ int HttpConnection::writeRespBodyv( IOVec &vector, int total ) IOVec & iov = m_response.getIov(); iov.append( vector ); total += totalHeader; - written = HttpIOLink::writev( iov, total ); + written = getStream()->writev( iov, total ); iov.pop_back(vector.len()); if ( written >= totalHeader ) { @@ -1634,7 +1739,7 @@ int HttpConnection::writeRespBodyv( IOVec &vector, int total ) } } else - written = HttpIOLink::writev( vector, total ); + written = getStream()->writev( vector, total ); if ( written > 0 ) m_response.written( written ); return written; @@ -1657,129 +1762,125 @@ static char s_errTimeout[] = // "http://www.litespeedtech.com\n" "\n"; - -int HttpConnection::detectTimeout() +int HttpConnection::detectKeepAliveTimeout( int delta ) { - register int c = 0; register const HttpServerConfig& config = HttpServerConfig::getInstance(); -// if ( D_ENABLED( DL_MEDIUM ) ) -// LOG_D((getLogger(), -// "[%s] HttpConnection::detectTimeout() ", -// getLogId() )); - int delta = DateTime::s_curTime - m_lReqTime; - switch(getState() ) + int c = 0; + if ( delta >= config.getKeepAliveTimeout() ) + { + if ( D_ENABLED( DL_MEDIUM ) ) + LOG_D((getLogger(), + "[%s] Keep-alive timeout, close!", + getLogId() )); + c = 1; + } + else if (( delta > 2)&&(m_iReqServed != 0 )) { - case HC_WAITING: - if ( delta >= config.getKeepAliveTimeout() ) + if ( HttpGlobals::getConnLimitCtrl()->getConnOverflow() ) { if ( D_ENABLED( DL_MEDIUM ) ) LOG_D((getLogger(), - "[%s] Keep-alive timeout, close!", + "[%s] Connections over flow, close connection!", getLogId() )); c = 1; + } - else if (( delta > 2)&&(m_iReqServed != 0 )) + else if ((int)m_pNtwkIOLink->getClientInfo()->getConns() > + (HttpGlobals::s_iConnsPerClientSoftLimit >> 1 ) ) { - if ( HttpGlobals::getConnLimitCtrl()->getConnOverflow() ) - { - if ( D_ENABLED( DL_MEDIUM ) ) - LOG_D((getLogger(), - "[%s] Connections over flow, close connection!", - getLogId() )); - c = 1; - - } - else if ((int)getClientInfo()->getConns() > - (HttpGlobals::s_iConnsPerClientSoftLimit >> 1 ) ) - { - if ( D_ENABLED( DL_MEDIUM ) ) - LOG_D((getLogger(), - "[%s] Connections is over the limit, close!", - getLogId() )); - c = 1; - } + if ( D_ENABLED( DL_MEDIUM ) ) + LOG_D((getLogger(), + "[%s] Connections is over the limit, close!", + getLogId() )); + c = 1; } - if ( c ) + } + if ( c ) + { + --HttpGlobals::s_iIdleConns; + getStream()->close(); + } + return c; +} + +int HttpConnection::detectConnectionTimeout( int delta ) +{ + register const HttpServerConfig& config = HttpServerConfig::getInstance(); + if ( DateTime::s_curTime > m_pNtwkIOLink->getActiveTime() + + config.getConnTimeout() ) + { + if ( m_pNtwkIOLink->getfd() != m_pNtwkIOLink->getPollfd()->fd ) + LOG_ERR(( getLogger(), + "[%s] BUG: fd %d does not match fd %d in pollfd!", + getLogId(), m_pNtwkIOLink->getfd(), m_pNtwkIOLink->getPollfd()->fd )); +// if ( D_ENABLED( DL_MEDIUM ) ) + if (( m_response.getBodySent() == 0 )|| !m_pNtwkIOLink->getEvents() ) { - --HttpGlobals::s_iIdleConns; - setPeerShutdown( IO_PEER_ERR ); - setState( HC_CLOSING ); - close(); + LOG_INFO((getLogger(), + "[%s] Connection idle time: %ld while in state: %d watching for event: %d," + "close!", + getLogId(), DateTime::s_curTime - m_pNtwkIOLink->getActiveTime(), getState(), m_pNtwkIOLink->getEvents() )); + m_request.dumpHeader(); + if ( m_pHandler ) + m_pHandler->dump(); + if ( getState() == HCS_READING_BODY ) + { + LOG_INFO((getLogger(), + "[%s] Request body size: %d, received: %d.", + getLogId(), m_request.getContentLength(), + m_request.getContentFinished() )); + } } - return c; - case HC_SHUTDOWN: - if ( delta > 1 ) + if (( getState() == HCS_PROCESSING )&&m_response.getBodySent() == 0 ) { - if ( D_ENABLED( DL_MEDIUM ) ) - LOG_D((getLogger(), "[%s] Shutdown time out!", getLogId() )); - closeSocket(); + IOVec iov; + iov.append( s_errTimeout, sizeof( s_errTimeout ) - 1 ); + getStream()->writev( iov, sizeof( s_errTimeout ) - 1 ); } - return 1; - case HC_CLOSING: + else + getStream()->setAbortedFlag(); closeConnection(); return 1; - case HC_READING: - case HC_READING_BODY: - if (!( getEvents() & POLLIN ) && allowRead()) - { - LOG_WARN(( getLogger(), "[%s] Oops! POLLIN is turned off for this HTTP connection " - "while reading request, turn it on, this should never happen!", getLogId() )); - continueRead(); - } + } + else + return 0; +} + +int HttpConnection::isAlive() +{ + if ( getStream()->isSpdy() ) + return 1; + return !m_pNtwkIOLink->detectClose(); + +} + + +int HttpConnection::detectTimeout() +{ +// if ( D_ENABLED( DL_MEDIUM ) ) +// LOG_D((getLogger(), +// "[%s] HttpConnection::detectTimeout() ", +// getLogId() )); + int delta = DateTime::s_curTime - m_lReqTime; + switch(getState() ) + { + case HCS_WAITING: + return detectKeepAliveTimeout( delta ); + case HCS_READING: + case HCS_READING_BODY: //fall through default: - -// if ( getClientInfo()->getAccess() == AC_BLOCK ) -// { -// LOG_INFO(( "[%s] Connection limit violation, access is denied, " -// "close existing connection!", getLogId() )); -// setPeerShutdown( IO_PEER_ERR ); -// closeConnection(); -// return 1; -// } - - if ( DateTime::s_curTime > getActiveTime() + - config.getConnTimeout() ) - { - if ( getfd() != getPollfd()->fd ) - LOG_ERR(( getLogger(), - "[%s] BUG: fd %d does not match fd %d in pollfd!", - getLogId(), getfd(), getPollfd()->fd )); -// if ( D_ENABLED( DL_MEDIUM ) ) - if (( m_response.getBodySent() == 0 )|| !getEvents() ) - { - LOG_INFO((getLogger(), - "[%s] Connection idle time: %ld while in state: %d watching for event: %d," - "close!", - getLogId(), DateTime::s_curTime - getActiveTime(), getState(), getEvents() )); - m_request.dumpHeader(); - if ( m_pHandler ) - m_pHandler->dump(); - if ( getState() == HC_READING_BODY ) - { - LOG_INFO((getLogger(), - "[%s] Request body size: %d, received: %d.", - getLogId(), m_request.getContentLength(), - m_request.getContentFinished() )); - } - } - if (( getState() == HC_PROCESSING )&&m_response.getBodySent() == 0 ) - { - IOVec iov; - iov.append( s_errTimeout, sizeof( s_errTimeout ) - 1 ); - HttpIOLink::writev( iov, sizeof( s_errTimeout ) - 1 ); - } - else - setPeerShutdown( IO_PEER_ERR ); - closeConnection(); - return 1; - } + return detectConnectionTimeout( delta); } return 0; } int HttpConnection::onTimerEx( ) { + if ( getState() == HCS_THROTTLING) + { + onWriteEx(); + } if ( detectTimeout() ) return 1; if ( m_pHandler ) @@ -1789,10 +1890,10 @@ int HttpConnection::onTimerEx( ) void HttpConnection::releaseRespCache() { - if ( m_pRespCache ) + if ( m_pRespBodyBuf ) { - HttpGlobals::getResManager()->recycle( m_pRespCache ); - m_pRespCache = NULL; + HttpGlobals::getResManager()->recycle( m_pRespBodyBuf ); + m_pRespBodyBuf = NULL; } } int HttpConnection::sendDynBody() @@ -1800,7 +1901,7 @@ int HttpConnection::sendDynBody() while( true ) { size_t toWrite; - char * pBuf = m_pRespCache->getReadBuffer( toWrite ); + char * pBuf = m_pRespBodyBuf->getReadBuffer( toWrite ); if ( toWrite > 0 ) { @@ -1812,7 +1913,7 @@ int HttpConnection::sendDynBody() len = allowed; if ( len <= 0 ) { - m_pRespCache->readUsed( toWrite ); + m_pRespBodyBuf->readUsed( toWrite ); continue; } } @@ -1827,7 +1928,7 @@ int HttpConnection::sendDynBody() m_lDynBodySent += ret; if ( ret >= len ) ret = toWrite; - m_pRespCache->readUsed( ret ); + m_pRespBodyBuf->readUsed( ret ); if ( ret < len ) { continueWrite(); @@ -1853,10 +1954,10 @@ int HttpConnection::sendDynBody() int HttpConnection::setupRespCache() { - if ( !m_pRespCache ) + if ( !m_pRespBodyBuf ) { - m_pRespCache = HttpGlobals::getResManager()->getVMemBuf(); - if ( !m_pRespCache ) + m_pRespBodyBuf = HttpGlobals::getResManager()->getVMemBuf(); + if ( !m_pRespBodyBuf ) { LOG_ERR(( getLogger(), "[%s] Failed to obtain VMemBuf, current pool size: %d," "capacity: %d.", @@ -1864,7 +1965,7 @@ int HttpConnection::setupRespCache() HttpGlobals::getResManager()->getVMemBufPoolCapacity() )); return -1; } - if ( m_pRespCache->reinit( + if ( m_pRespBodyBuf->reinit( m_response.getContentLen() ) ) { LOG_ERR(( getLogger(), "[%s] Failed to initialize VMemBuf, response body len: %ld.", getLogId(), m_response.getContentLen() )); @@ -1901,7 +2002,7 @@ int HttpConnection::setupGzipFilter() int HttpConnection::setupGzipBuf( int type ) { - if ( m_pRespCache ) + if ( m_pRespBodyBuf ) { if ( D_ENABLED( DL_LESS ) ) LOG_D(( getLogger(), "[%s] %s response body!", @@ -1921,7 +2022,7 @@ int HttpConnection::setupGzipBuf( int type ) releaseGzipBuf(); } } - m_iRespBodyCacheOffset = m_pRespCache->getCurWOffset(); + m_iRespBodyCacheOffset = m_pRespBodyBuf->getCurWOffset(); if ( !m_pGzipBuf ) { if (type == GzipBuf::GZIP_DEFLATE) @@ -1931,7 +2032,7 @@ int HttpConnection::setupGzipBuf( int type ) } if ( m_pGzipBuf ) { - m_pGzipBuf->setCompressCache( m_pRespCache ); + m_pGzipBuf->setCompressCache( m_pRespBodyBuf ); if (( m_pGzipBuf->init( type, HttpServerConfig::getInstance().getCompressLevel() ) == 0 )&& ( m_pGzipBuf->beginStream() == 0 )) @@ -1982,8 +2083,8 @@ int HttpConnection::appendDynBody( int inplace, const char * pBuf, int len ) { if ( inplace ) { - if ( m_pRespCache ) - m_pRespCache->writeUsed( len ); + if ( m_pRespBodyBuf ) + m_pRespBodyBuf->writeUsed( len ); } else ret = appendRespCache( pBuf, len ); @@ -1999,7 +2100,7 @@ int HttpConnection::appendRespCache( const char * pBuf, int len ) size_t iCacheSize; while( len > 0 ) { - pCache = m_pRespCache->getWriteBuffer( iCacheSize ); + pCache = m_pRespBodyBuf->getWriteBuffer( iCacheSize ); if ( pCache ) { int ret = len; @@ -2010,7 +2111,7 @@ int HttpConnection::appendRespCache( const char * pBuf, int len ) memmove( pCache, pBuf, ret ); pBuf += ret; len -= ret; - m_pRespCache->writeUsed( ret ); + m_pRespBodyBuf->writeUsed( ret ); } else { @@ -2023,7 +2124,7 @@ int HttpConnection::appendRespCache( const char * pBuf, int len ) int HttpConnection::shouldSuspendReadingResp() { - return m_pRespCache->getCurWBlkPos() >= 2048 * 1024; + return m_pRespBodyBuf->getCurWBlkPos() >= 2048 * 1024; } void HttpConnection::resetRespBodyBuf() @@ -2034,8 +2135,8 @@ void HttpConnection::resetRespBodyBuf() m_pGzipBuf->resetCompressCache(); else { - m_pRespCache->rewindReadBuf(); - m_pRespCache->rewindWriteBuf(); + m_pRespBodyBuf->rewindReadBuf(); + m_pRespBodyBuf->rewindWriteBuf(); } } } @@ -2048,7 +2149,7 @@ static char achOverBodyLimitError[] = int HttpConnection::checkRespSize( int nobuffer ) { int ret = 0; - int curLen = m_pRespCache->writeBufSize(); + int curLen = m_pRespBodyBuf->writeBufSize(); if ((nobuffer&&(curLen > 0))||(curLen > 1460 )) { if ( curLen > HttpServerConfig::getInstance().getMaxDynRespLen() ) @@ -2076,7 +2177,7 @@ int HttpConnection::checkRespSize( int nobuffer ) } else { - setState( HC_WRITING ); + setState( HCS_WRITING ); //sendResp(); continueWrite(); } @@ -2115,7 +2216,7 @@ int HttpConnection::endDynResp( int cacheable ) else { //sendResp(); - setState( HC_WRITING ); + setState( HCS_WRITING ); continueWrite(); } } @@ -2133,8 +2234,6 @@ int HttpConnection::prepareDynRespHeader( int complete, int nobuffer ) m_response.getIov().clear(); if ( sendBody() ) { - if ( getGzipBuf() && (getGzipBuf()->getType() == GzipBuf::GZIP_DEFLATE) ) - m_response.addGzipEncodingHeader(); if (( complete )&&(( getRespCache()->writeBufSize() > 0 )|| m_response.getContentLen() == 0)) { @@ -2151,9 +2250,10 @@ int HttpConnection::prepareDynRespHeader( int complete, int nobuffer ) { setupChunkOS( nobuffer ); } + if ( getGzipBuf() && (getGzipBuf()->getType() == GzipBuf::GZIP_DEFLATE) ) + m_response.addGzipEncodingHeader(); } m_response.prepareHeaders( &m_request ); - m_response.endHeader(); m_response.finalizeHeader( m_request.getVersion(), m_request.getStatusCode()); return 0; } @@ -2306,3 +2406,23 @@ int HttpConnection::execExtCmd( const char * pCmd, int len ) // // } +int HttpConnection::getServerAddrStr( char * pBuf, int len ) +{ + char achAddr[128]; + socklen_t addrlen = 128; + if ( getsockname( m_pNtwkIOLink->getfd(), (struct sockaddr *) achAddr, &addrlen ) == -1 ) + { + return 0; + } + + if (( AF_INET6 == ((struct sockaddr *)achAddr)->sa_family )&& + ( IN6_IS_ADDR_V4MAPPED( &((struct sockaddr_in6 *)achAddr)->sin6_addr )) ) + { + ((struct sockaddr *)achAddr)->sa_family = AF_INET; + ((struct sockaddr_in *)achAddr)->sin_addr.s_addr = *((in_addr_t *)&achAddr[20]); + } + + if ( GSockAddr::ntop( (struct sockaddr *)achAddr, pBuf, len ) == NULL ) + return 0; + return strlen( pBuf ); +} diff --git a/src/http/httpconnection.h b/src/http/httpconnection.h index 8be64d9b5..75e5ec01b 100644 --- a/src/http/httpconnection.h +++ b/src/http/httpconnection.h @@ -20,11 +20,11 @@ #include -#include #include #include #include - +#include +#include class ReqHandler; class VHostMap; @@ -34,13 +34,24 @@ class ExtWorker; class VMemBuf; class GzipBuf; class SSIScript; +class NtwkIOLink; + +enum httpConState { + HCS_WAITING, + HCS_READING, + HCS_READING_BODY, + HCS_EXT_AUTH, + HCS_THROTTLING, + HCS_PROCESSING, + HCS_REDIRECT, + HCS_WRITING, + HCS_AIO_PENDING, + HCS_AIO_COMPLETE, + HCS_COMPLETE, +}; -class HttpConnection : public HttpIOLink, public InputStream -{ - - AutoStr2 m_logID; - LOG4CXX_NS::Logger * m_pLogger; - +class HttpConnection : public HioStreamHandler +{ HttpReq m_request; HttpResp m_response; @@ -52,16 +63,16 @@ class HttpConnection : public HttpIOLink, public InputStream off_t m_lDynBodySent; int m_iRespBodyCacheOffset; - VMemBuf * m_pRespCache; + VMemBuf * m_pRespBodyBuf; GzipBuf * m_pGzipBuf; long m_lReqTime; int32_t m_iReqTimeMs; unsigned short m_iReqServed; - unsigned short m_iRemotePort; - int m_iLogIdBuilt; //int m_accessGranted; + httpConState m_iState; + NtwkIOLink * m_pNtwkIOLink; HttpConnection( const HttpConnection& rhs ); void operator=( const HttpConnection& rhs ); @@ -74,8 +85,13 @@ class HttpConnection : public HttpIOLink, public InputStream void cleanUpHandler(); void nextRequest(); - void closeConnection( int cancel = 0); + int updateClientInfoFromProxyHeader( const char * pProxyHeader ); + +public: + void closeConnection(); void recycle(); + +private: int checkAuthorizer( const HttpHandler * pHandler ); int assignHandler( const HttpHandler * pHandler ); int readReqBody( char * pBuf, int size ); @@ -86,7 +102,9 @@ class HttpConnection : public HttpIOLink, public InputStream int readToHeaderBuf(); void sendHttpError( const char * pAdditional ); int detectTimeout(); - + + int sendSpdyHeaders(); + //int cacheWrite( const char * pBuf, int size ); //int writeRespBuf(); @@ -105,21 +123,47 @@ class HttpConnection : public HttpIOLink, public InputStream const AuthRequired * pRequired, int resume); void logAccess( int cancelled ); + int detectKeepAliveTimeout( int delta ); + int detectConnectionTimeout( int delta ); + + +public: + NtwkIOLink * getNtwkIOLink() const { return m_pNtwkIOLink; } + void setNtwkIOLink( NtwkIOLink * p ) { m_pNtwkIOLink = p; } + //below are wrapper functions + SSLConnection* getSSL() { return m_pNtwkIOLink->getSSL(); } + bool isSSL() const { return m_pNtwkIOLink->isSSL(); } + const char * getPeerAddrString() const { return m_pNtwkIOLink->getPeerAddrString(); } + int getPeerAddrStrLen() const { return m_pNtwkIOLink->getPeerAddrStrLen(); } + const struct sockaddr * getPeerAddr() const { return m_pNtwkIOLink->getPeerAddr(); } + + void suspendRead() { getStream()->suspendRead(); }; + void continueRead() { getStream()->continueRead(); }; + void suspendWrite() { getStream()->suspendWrite(); }; + void continueWrite() { getStream()->continueWrite(); }; + void switchWriteToRead() { getStream()->switchWriteToRead(); }; + + void suspendEventNotify() { m_pNtwkIOLink->suspendEventNotify(); }; + void resumeEventNotify() { m_pNtwkIOLink->resumeEventNotify(); }; + void tryRead() { m_pNtwkIOLink->tryRead(); }; + off_t getBytesRecv() const { return getStream()->getBytesRecv(); } + off_t getBytesSent() const { return getStream()->getBytesSent(); } + ClientInfo * getClientInfo() const { return m_pNtwkIOLink->getClientInfo(); } + + httpConState getState() const { return m_iState; } + void setState( httpConState state ) { m_iState = state; } + int getServerAddrStr( char * pBuf, int len ); + int isAlive(); -protected: - public: - void setupChunkOS(int nobuffer); HttpConnection(); ~HttpConnection(); - - void setRemotePort( unsigned short port ) - { m_iRemotePort = port; m_iLogIdBuilt = 0; } + unsigned short getRemotePort() const - { return m_iRemotePort; } + { return m_pNtwkIOLink->getRemotePort(); }; void setVHostMap( const VHostMap* pMap ) { m_iReqServed = 0; @@ -147,6 +191,7 @@ class HttpConnection : public HttpIOLink, public InputStream int onReadEx(); int onWriteEx(); int onInitConnected(); + int onCloseEx(); int redirect( const char * pNewURL, int len, int alloc = 0 ); int getHandler( const char * pURI, ReqHandler* &pHandler ); @@ -157,23 +202,9 @@ class HttpConnection : public HttpIOLink, public InputStream int onTimerEx(); //void accessGranted() { m_accessGranted = 1; } - void changeHandler() - { - setState( HC_REDIRECT ); - } - - void setLogger( LOG4CXX_NS::Logger* pLogger ) - { m_pLogger = pLogger; } - LOG4CXX_NS::Logger* getLogger() const - { return m_pLogger; } - - const char * buildLogId(); - const char * getLogId() - { - if ( m_iLogIdBuilt ) - return m_logID.c_str(); - return buildLogId(); - } + void changeHandler() { setState( HCS_REDIRECT ); }; + + //const char * buildLogId(); void httpError( int code, const char * pAdditional = NULL) { m_request.setStatusCode( code ); @@ -204,7 +235,7 @@ class HttpConnection : public HttpIOLink, public InputStream int prepareDynRespHeader( int complete, int nobuffer ); int setupDynRespBodyBuf( int &iRespState ); GzipBuf * getGzipBuf() const { return m_pGzipBuf; } - VMemBuf * getRespCache() const { return m_pRespCache; } + VMemBuf * getRespCache() const { return m_pRespBodyBuf; } off_t getDynBodySent() const { return m_lDynBodySent; } int processModSecRules( int phase ); int flushDynBody( int nobuff ); @@ -217,8 +248,13 @@ class HttpConnection : public HttpIOLink, public InputStream int flushDynBodyChunk(); //int writeConnStatus( char * pBuf, int bufLen ); + void resetResp() + { getResp()->reset( (RespHeader::FORMAT)getStream()->getProtocol() ); } + + LOG4CXX_NS::Logger* getLogger() const { return getStream()->getLogger(); } + + const char * getLogId() { return getStream()->getLogId(); } - }; #endif diff --git a/src/http/httpcontext.cpp b/src/http/httpcontext.cpp index 19c6d0a87..5700db2ac 100644 --- a/src/http/httpcontext.cpp +++ b/src/http/httpcontext.cpp @@ -34,20 +34,20 @@ #include #include #include - #include #include #include #include #include + CtxInt HttpContext::s_defaultInternal = { NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL } ; + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, } ; HttpContext::HttpContext() : m_iConfigBits( 0 ) - , m_iConfigBits2( 0 ) , m_pURIMatch( NULL ) , m_pMatchList( NULL ) , m_pFilesMatchStr( NULL ) @@ -57,10 +57,11 @@ HttpContext::HttpContext() , m_bAllowBrowse( BIT_ALLOW_BROWSE | BIT_INCLUDES | BIT_INCLUDES_NOEXEC ) , m_redirectCode( -1 ) , m_iSetUidMode( 0 ) - , m_iChrootMode( 0 ) - , m_iEnableRewrite( REWRITE_INHERIT_ON ) + , m_iConfigBits2( 0 ) , m_iRewriteEtag( 0 ) , m_iSecRules( 0 ) + , m_iChrootMode( 0 ) + , m_iEnableRewrite( REWRITE_INHERIT_ON ) // , m_iFilesMatchCtx( 0 ) , m_iCacheable( 1 ) , m_lHTALastMod( 0 ) @@ -131,7 +132,7 @@ void HttpContext::releaseHTAConf() int HttpContext::set( const char * pURI, const char * pLocation, - const HttpHandler * pHandler, bool allowBrowse, int regex) + const HttpHandler * pHandler, bool browse, int regex) { if (( pURI == NULL )) return EINVAL; @@ -177,11 +178,7 @@ int HttpContext::set( const char * pURI, const char * pLocation, } m_sContextURI.setLen( len ); m_pHandler = pHandler; - if(allowBrowse) - m_bAllowBrowse |= BIT_ALLOW_BROWSE; - else - m_bAllowBrowse &= (~BIT_ALLOW_BROWSE); - //m_bAllowBrowse = allowBrowse; + allowBrowse(browse); return 0; } @@ -899,3 +896,12 @@ void HttpContext::getAAAData( struct AAAData & data ) const memmove( &data, &m_pInternal->m_pHTAuth, sizeof( AAAData ) ); } +void HttpContext::setGSockAddr(GSockAddr &gsockAddr) +{ + if ( !allocateInternal() ) + { + m_pInternal->m_GSockAddr = gsockAddr; + m_iConfigBits |= BIT_GSOCKADDR; + } +} + diff --git a/src/http/httpcontext.h b/src/http/httpcontext.h index 97b7f3224..b80da85e2 100644 --- a/src/http/httpcontext.h +++ b/src/http/httpcontext.h @@ -22,7 +22,7 @@ #include #include #include - +#include "socket/gsockaddr.h" #include class AccessControl; @@ -41,7 +41,6 @@ class StatusUrlMap; class AutoBuf; class SSIConfig; - #define UID_SERVER 0 #define UID_FILE 1 #define UID_DOCROOT 2 @@ -86,6 +85,8 @@ class SSIConfig; #define BIT_FILES_MATCH (1<<25) #define BIT_EXTRA_HEADER (1<<26) #define BIT_GEO_IP (1<<28) +#define BIT_GSOCKADDR (1<<29) + #define BIT_RAILS_CONTEXT (1<<6) @@ -151,6 +152,7 @@ typedef struct _CTX_INT ContextList * m_pFilesMatchList; AutoBuf * m_pExtraHeader; SSIConfig * m_pSSIConfig; + GSockAddr m_GSockAddr; } CtxInt; class HttpContext @@ -234,9 +236,15 @@ class HttpContext const HttpHandler * getHandler() const { return m_pHandler; } - char allowBrowse() const { return m_bAllowBrowse; } - void allowBrowse( int browse ) { m_bAllowBrowse = browse; } - + char allowBrowse() const { return (m_bAllowBrowse & BIT_ALLOW_BROWSE); } + void allowBrowse( int browse ) + { + if(browse) + m_bAllowBrowse |= BIT_ALLOW_BROWSE; + else + m_bAllowBrowse &= (~BIT_ALLOW_BROWSE); + } + ExpiresCtrl& getExpires() { return m_expires; } const ExpiresCtrl& getExpires() const { return m_expires; } @@ -375,6 +383,9 @@ class HttpContext const AutoBuf * getExtraHeaders() const { return m_pInternal->m_pExtraHeader; } + const GSockAddr *getGSockAddr() const { return &m_pInternal->m_GSockAddr; } + void setGSockAddr(GSockAddr &gsockAddr); + void setGeoIP( int a ) { if ( a ) m_iSetUidMode |= CTX_GEOIP_ON; diff --git a/src/http/httpdefs.h b/src/http/httpdefs.h index 788087709..f36addf73 100644 --- a/src/http/httpdefs.h +++ b/src/http/httpdefs.h @@ -28,9 +28,9 @@ #define THROTTLE_UNIT 4096 #define MAX_REQ_HEADER_BUF_LEN (8192*2 - HEADER_BUF_PAD) -#define MAX_REQ_BODY_LEN (1024 * 1024 * 1024) -#define MAX_DYN_RESP_LEN 1024 * 1024 * 1024 -#define MAX_DYN_RESP_HEADER_LEN 8192 +#define MAX_REQ_BODY_LEN (LONG_MAX - 1) +#define MAX_DYN_RESP_LEN LONG_MAX +#define MAX_DYN_RESP_HEADER_LEN 65536 #define DEFAULT_URL_LEN 2048 #define DEFAULT_REQ_HEADER_BUF_LEN 8192 diff --git a/src/http/httpextconnector.cpp b/src/http/httpextconnector.cpp index 1b882b69c..1ade27af6 100644 --- a/src/http/httpextconnector.cpp +++ b/src/http/httpextconnector.cpp @@ -277,21 +277,6 @@ int HttpExtConnector::processRespBodyData( int inplace, const char * pBuf, int l int HttpExtConnector::extInputReady() { - // int ret; - // char * pCache; - // size_t iCacheSize; - // while( true ) - // { - // pCache = m_pRespCache->getWriteBuffer( iCacheSize ); - // ret = getProcessor()->readResp( pCache, iCacheSize ); - // if ( ret > 0 ) - // { - // m_pRespCache->writeUsed( ret ); - // } - // if ( (size_t)ret < iCacheSize ) - // break; - // } - // getHttpConn()->continueWrite(); return 0; } @@ -536,6 +521,7 @@ int HttpExtConnector::tryRecover() { ExtWorker * pWorker = pLB->selectWorker(m_pHttpConn, this); if ( D_ENABLED( DL_LESS ) ) + { if ( pWorker ) { LOG_D(( "[%s] [LB] retry worker: [%s]", @@ -545,6 +531,7 @@ int HttpExtConnector::tryRecover() { LOG_D(( "[%s] [LB] Backup worker is unavailable." )); } + } setWorker( pWorker ); if ( D_ENABLED( DL_LESS ) ) LOG_D(( "[%s] trying to recover from connection problem, attempt: #%d!", @@ -620,6 +607,7 @@ int HttpExtConnector::sendReqBody() VMemBuf * pVMemBuf = pReq->getBodyBuf(); size_t size; char * pBuf; + int count = 0; while(( (pBuf = pVMemBuf->getReadBuffer(size)) != NULL )&&( size > 0 )) { int written = getProcessor()->sendReqBody(pBuf, size ); @@ -632,7 +620,7 @@ int HttpExtConnector::sendReqBody() LOG_D(( getLogger(), "[%s] processor sent request body %d bytes, total sent: %d\n", getLogId(), written, m_iReqBodySent )); - if ( written != (int)size ) + if (( written != (int)size )||( ++count == 10 )) { if ( written != -1 ) getProcessor()->continueWrite(); @@ -736,11 +724,6 @@ void HttpExtConnector::dump() "left in buffer: %ld, attempts: %d." , getLogId(), m_iState, m_iReqBodySent, m_pHttpConn->getResp()->getContentLen(), m_pHttpConn->getDynBodySent(), (m_pHttpConn->getRespCache())?m_pHttpConn->getRespCache()->writeBufSize():0, getAttempts() )); -// LOG_INFO(( getLogger(), "[%s] HttpExtConnector state: %d, " -// "request body sent: %d, response body size: %d, response body sent:%d, " -// "left in buffer: %ld, attempts: %d." -// , getLogId(), m_iState, m_iReqBodySent, m_iRespBodyLen, m_iRespBodySent, -// (m_pRespCache)?m_pRespCache->writeBufSize():0, getAttempts() )); if ( m_pProcessor ) { m_pProcessor->dump(); @@ -755,22 +738,10 @@ int HttpExtConnector::dumpAborted() return ( m_pProcessor != NULL); } -#include int HttpExtConnector::isAlive() { - char ch; - HttpConnection * pConn = getHttpConn(); - pConn->resumeEventNotify(); - if (( !::recv( pConn->getfd(), &ch, 1, MSG_PEEK ) )|| - ( pConn->getClientInfo()->getAccess() == AC_BLOCK )) - { - pConn->setPeerShutdown( IO_PEER_ERR ); - pConn->setState( HC_CLOSING ); - pConn->continueWrite(); - return 0; - } - return 1; + return getHttpConn()->isAlive(); } void HttpExtConnector::setHttpError( int error ) @@ -778,13 +749,6 @@ void HttpExtConnector::setHttpError( int error ) errResponse( error, NULL ); } -int HttpExtConnector::convertFileBackedToInMemory() -{ - if ( m_pHttpConn->getRespCache()) - return m_pHttpConn->getRespCache()->convertFileBackedToInMemory(); - return -1; -} - diff --git a/src/http/httpextconnector.h b/src/http/httpextconnector.h index 5f7fe249f..7c24d415a 100644 --- a/src/http/httpextconnector.h +++ b/src/http/httpextconnector.h @@ -143,7 +143,6 @@ class HttpExtConnector : public ReqHandler, public ExtRequest { return (m_iState & (HEC_FWD_REQ_HEADER|HEC_FWD_REQ_BODY)); } int getRespBodyLen() const { return m_iRespBodyLen; } int flushResp(); - int convertFileBackedToInMemory(); }; #endif diff --git a/src/http/httpglobals.cpp b/src/http/httpglobals.cpp index 34be838d9..3f01f9b73 100644 --- a/src/http/httpglobals.cpp +++ b/src/http/httpglobals.cpp @@ -40,6 +40,10 @@ ClientCache HttpGlobals::s_clients( 1000 ); #include HttpConnPool::Pool HttpConnPool::s_pool( 20, 20 ); +#include +#include +NtwkIoLinkPool::Pool NtwkIoLinkPool::s_pool( 20, 20 ); + #include int HttpGlobals::s_iConnsPerClientSoftLimit = INT_MAX; int HttpGlobals::s_iOverLimitGracePeriod = 10; @@ -62,61 +66,61 @@ long HttpGlobals::s_lSSLBytesWritten = 0; int HttpGlobals::s_iIdleConns = 0; ReqStats HttpGlobals::s_reqStats; -#include -class HttpIOLink::fn_list HttpIOLink::s_normal +#include +class NtwkIOLink::fn_list NtwkIOLink::s_normal ( - HttpIOLink::readEx, - HttpIOLink::writevEx, - HttpIOLink::onWrite, - HttpIOLink::onRead, - HttpIOLink::close_, - HttpIOLink::onTimer_ + NtwkIOLink::readEx, + NtwkIOLink::writevEx, + NtwkIOLink::onWrite, + NtwkIOLink::onRead, + NtwkIOLink::close_, + NtwkIOLink::onTimer_ ); -class HttpIOLink::fn_list HttpIOLink::s_normalSSL +class NtwkIOLink::fn_list NtwkIOLink::s_normalSSL ( - HttpIOLink::readExSSL, - HttpIOLink::writevExSSL, - HttpIOLink::onWriteSSL, - HttpIOLink::onReadSSL, - HttpIOLink::closeSSL, - HttpIOLink::onTimer_ + NtwkIOLink::readExSSL, + NtwkIOLink::writevExSSL, + NtwkIOLink::onWriteSSL, + NtwkIOLink::onReadSSL, + NtwkIOLink::closeSSL, + NtwkIOLink::onTimer_ ); -class HttpIOLink::fn_list HttpIOLink::s_throttle +class NtwkIOLink::fn_list NtwkIOLink::s_throttle ( - HttpIOLink::readExT, - HttpIOLink::writevExT, - HttpIOLink::onWriteT, - HttpIOLink::onReadT, - HttpIOLink::close_, - HttpIOLink::onTimer_T + NtwkIOLink::readExT, + NtwkIOLink::writevExT, + NtwkIOLink::onWriteT, + NtwkIOLink::onReadT, + NtwkIOLink::close_, + NtwkIOLink::onTimer_T ); -class HttpIOLink::fn_list HttpIOLink::s_throttleSSL +class NtwkIOLink::fn_list NtwkIOLink::s_throttleSSL ( - HttpIOLink::readExSSL_T, - HttpIOLink::writevExSSL_T, - HttpIOLink::onWriteSSL_T, - HttpIOLink::onReadSSL_T, - HttpIOLink::closeSSL, - HttpIOLink::onTimerSSL_T + NtwkIOLink::readExSSL_T, + NtwkIOLink::writevExSSL_T, + NtwkIOLink::onWriteSSL_T, + NtwkIOLink::onReadSSL_T, + NtwkIOLink::closeSSL, + NtwkIOLink::onTimerSSL_T ); -class HttpIOLink::fn_list_list HttpIOLink::s_fn_list_list_normal +class NtwkIOLink::fn_list_list NtwkIOLink::s_fn_list_list_normal ( - &HttpIOLink::s_normal, - &HttpIOLink::s_normalSSL + &NtwkIOLink::s_normal, + &NtwkIOLink::s_normalSSL ); -class HttpIOLink::fn_list_list HttpIOLink::s_fn_list_list_throttle +class NtwkIOLink::fn_list_list NtwkIOLink::s_fn_list_list_throttle ( - &HttpIOLink::s_throttle, - &HttpIOLink::s_throttleSSL + &NtwkIOLink::s_throttle, + &NtwkIOLink::s_throttleSSL ); -class HttpIOLink::fn_list_list *HttpIOLink::s_pCur_fn_list_list = - &HttpIOLink::s_fn_list_list_normal; +class NtwkIOLink::fn_list_list *NtwkIOLink::s_pCur_fn_list_list = + &NtwkIOLink::s_fn_list_list_normal; #include HttpServerConfig HttpServerConfig::s_config; @@ -167,7 +171,7 @@ int HttpHeader::s_iHeaderLen[H_HEADER_END+1] = 6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent 13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17, 2, 6, 12, 19, 4, //date 7, 7, 7, 5, 16, 16, 16, 11, 13, 7, 13, //last-modified - 0,0,0,8,0,16,0,6,0,0,6,0 + 13,3,4,8,18,16,11,6,4,16,10,11,6,20,19,25,0 }; @@ -185,18 +189,23 @@ SSIEngine s_ssiHandler; StaticFileCache HttpGlobals::s_staticFileCache( 1000 ); #include -char HttpResp::s_sCommonHeaders[128]; -int HttpResp::s_iCommonHeaderLen = 16; -char HttpResp::s_sKeepAliveHeader[25] = - "Connection: Keep-Alive\r\n"; - +HttpRespHeaders HttpResp::s_CommonHeaders[3]; + +// char HttpResp::s_sKeepAliveHeader[2][25] = +// { "Connection: Keep-Alive\r\n", "\x00\x0A""Connection\x00\x0A""Keep-Alive"}; +// char HttpResp::s_sConnCloseHeader[2][20] = +// {"Connection: close\r\n", "\x00\x0A""Connection\x00\x05""close"}; +// char HttpResp::s_chunked[2][29] = +// {"Transfer-Encoding: chunked\r\n", "\x00\x11""Transfer-Encoding\x00\x07""chunked"}; +// char HttpResp::s_sGzipEncodingHeader[2][48] = +// {"Content-Encoding: gzip\r\nVary: Accept-Encoding\r\n", +// "\x00\x10""Content-Encoding\x00\x04""gzip\x00\x04""Vary\x00\x0F""Accept-Encoding"}; +char HttpResp::s_sKeepAliveHeader[25] = "Connection: Keep-Alive\r\n"; char HttpResp::s_sConnCloseHeader[20] = "Connection: close\r\n"; char HttpResp::s_chunked[29] = "Transfer-Encoding: chunked\r\n"; +char HttpResp::s_sGzipEncodingHeader[48] = "Content-Encoding: gzip\r\nVary: Accept-Encoding\r\n"; -char HttpResp::s_sGzipEncodingHeader[48] = "Content-Encoding: gzip\r\n" - "Vary: Accept-Encoding\r\n"; - #include #include @@ -463,6 +472,7 @@ int HttpGlobals::s_dnsLookup = 1; int HttpGlobals::s_children = 1; int HttpGlobals::s_503Errors = 0; int HttpGlobals::s_503AutoFix = 1; +int HttpGlobals::s_useProxyHeader = 0; int HttpGlobals::s_rubyProcLimit = 10; int HttpGlobals::s_railsAppLimit = 1; diff --git a/src/http/httpglobals.h b/src/http/httpglobals.h index 1b5f59a7d..d337b6b2a 100644 --- a/src/http/httpglobals.h +++ b/src/http/httpglobals.h @@ -94,6 +94,7 @@ class HttpGlobals static int s_children; static int s_503Errors; static int s_503AutoFix; + static int s_useProxyHeader; static int s_tmPrevToken; static int s_tmToken; diff --git a/src/http/httpheader.cpp b/src/http/httpheader.cpp index e715b2649..af37cab37 100644 --- a/src/http/httpheader.cpp +++ b/src/http/httpheader.cpp @@ -178,7 +178,13 @@ size_t HttpHeader::getRespHeaderIndex( const char * pHeader ) idx = CGI_STATUS; else if ( strncasecmp( pHeader, "erver", 5 ) == 0 ) idx = H_SERVER; - + else if ( strncasecmp( pHeader, "et-cookie", 9 ) == 0 ) + { + if ( *(pHeader + 9) == '2' ) + idx = H_SET_COOKIE2; + else + idx = H_SET_COOKIE; + } break; case 't': if ( strncasecmp( pHeader, "ransfer-encoding", 16 ) == 0 ) diff --git a/src/http/httpheader.h b/src/http/httpheader.h index 265c67274..de69eeb74 100644 --- a/src/http/httpheader.h +++ b/src/http/httpheader.h @@ -87,7 +87,12 @@ class HttpHeader H_SERVER, H_VARY, H_WWW_AUTHENTICATE, + H_SET_COOKIE, + H_SET_COOKIE2, CGI_STATUS, + H_LITESPEED_LOCATION, + H_CONTENT_DISPOSITION, + H_LITESPEED_CACHE_CONTROL, H_HEADER_END }; static size_t getIndex( const char * pHeader ); diff --git a/src/http/httplistener.cpp b/src/http/httplistener.cpp index 59fe75c45..f0b072a44 100644 --- a/src/http/httplistener.cpp +++ b/src/http/httplistener.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -362,8 +363,8 @@ int HttpListener::batchAddConn( struct conn_data * pBegin, } if ( n <= 0 ) return 0; - HttpConnection* pConns[CONN_BATCH_SIZE]; - int ret = HttpConnPool::getConnections( pConns, n); + NtwkIOLink* pConns[CONN_BATCH_SIZE]; + int ret = NtwkIoLinkPool::get( pConns, n); pCur = pBegin; if ( ret <= 0 ) { @@ -380,8 +381,8 @@ int HttpListener::batchAddConn( struct conn_data * pBegin, } return -1; } - HttpConnection** pConnEnd = &pConns[ret]; - HttpConnection** pConnCur = pConns; + NtwkIOLink** pConnEnd = &pConns[ret]; + NtwkIOLink** pConnCur = pConns; VHostMap * pMap; int flag = HttpGlobals::getMultiplexer()->getFLTag(); while( pCur < pEnd ) @@ -390,7 +391,7 @@ int HttpListener::batchAddConn( struct conn_data * pBegin, if ( fd != -1 ) { assert( pConnCur < pConnEnd ); - HttpConnection * pConn = *pConnCur; + NtwkIOLink * pConn = *pConnCur; if ( m_pSubIpMap ) { @@ -424,7 +425,7 @@ int HttpListener::batchAddConn( struct conn_data * pBegin, } if ( pConnCur < pConnEnd ) { - HttpConnPool::recycle( pConnCur, pConnEnd - pConnCur); + NtwkIoLinkPool::recycle( pConnCur, pConnEnd - pConnCur); } return 0; @@ -456,7 +457,7 @@ int HttpListener::addConnection( struct conn_data * pCur, int *iCount ) --(*iCount); return 0; } - HttpConnection* pConn = HttpConnPool::getConnection(); + NtwkIOLink* pConn = NtwkIoLinkPool::get(); if ( !pConn ) { ERR_NO_MEM( "HttpConnPool::getConnection()" ); @@ -476,7 +477,7 @@ int HttpListener::addConnection( struct conn_data * pCur, int *iCount ) pConn->setRemotePort( ntohs( ((sockaddr_in *)(pCur->achPeerAddr))->sin_port) ); if ( pConn->setLink( pCur->fd, pCur->pInfo, pMap->getSSLContext() ) ) { - HttpConnPool::recycle( pConn ); + NtwkIoLinkPool::recycle( pConn ); close( fd ); --(*iCount); return -1; diff --git a/src/http/httplistener.h b/src/http/httplistener.h index 9b61c9fcb..f68d6ae15 100644 --- a/src/http/httplistener.h +++ b/src/http/httplistener.h @@ -57,6 +57,9 @@ class HttpListener : public EventReactor, public LogTracker int checkAccess( struct conn_data * pData ); int setSockAttr( int fd, GSockAddr &addr ); VHostMap * getSubMap( int fd ); + +protected: + virtual const char * buildLogId() { return NULL; }; public: explicit HttpListener( const char * pName, const char * pAddr ); diff --git a/src/http/httplistenerlist.cpp b/src/http/httplistenerlist.cpp index 9e6ac3c58..8f2736b17 100644 --- a/src/http/httplistenerlist.cpp +++ b/src/http/httplistenerlist.cpp @@ -298,7 +298,6 @@ int HttpListenerList::writeStatusReport( int fd ) { iterator iter; iterator iterEnd = end(); - char achBuf[1024]; for( iter = begin(); iter != iterEnd; ++iter ) { if ( (*iter)->writeStatusReport( fd ) == -1 ) diff --git a/src/http/httpmime.cpp b/src/http/httpmime.cpp index 07f1c653d..807bbfd40 100644 --- a/src/http/httpmime.cpp +++ b/src/http/httpmime.cpp @@ -467,7 +467,7 @@ void MIMEMap::removeMIME( MIMESetting * pMIME ) { char * p; iterator iter = findSubMap( (char *)pMIME->getMIME()->c_str(), p ); - if ( iter = end() ) + if ( iter == end() ) return; iter.second()->remove( p + 1 ); } diff --git a/src/http/httprange.cpp b/src/http/httprange.cpp index 8acb98e5f..a6a88a548 100644 --- a/src/http/httprange.cpp +++ b/src/http/httprange.cpp @@ -262,11 +262,12 @@ int HttpRange::parse( const char * pRange ) return 0; } +//Content-Range: int HttpRange::getContentRangeString( int n, char * pBuf, int len ) const { char * pBegin = pBuf; int ret; - ret = safe_snprintf( pBuf, len, "%s", "Content-Range: bytes " ); + ret = safe_snprintf( pBuf, len, "%s", "bytes " ); pBuf += ret; len -= ret; ret = 0; @@ -277,7 +278,7 @@ int HttpRange::getContentRangeString( int n, char * pBuf, int len ) const if ( m_lEntityLen == -1 ) return -1; else - ret = safe_snprintf( pBuf, len, "*/%ld\r\n", m_lEntityLen ); + ret = safe_snprintf( pBuf, len, "*/%ld", m_lEntityLen ); } else { @@ -289,15 +290,13 @@ int HttpRange::getContentRangeString( int n, char * pBuf, int len ) const return -1; if ( m_lEntityLen >= 0 ) { - ret = safe_snprintf( pBuf, len, "%ld\r\n", m_lEntityLen ); + ret = safe_snprintf( pBuf, len, "%ld", m_lEntityLen ); } else { if ( len > 4 ) { *pBuf++ = '*'; - *pBuf++ = '\r'; - *pBuf++ = '\n'; *pBuf = 0; } else diff --git a/src/http/httpreq.cpp b/src/http/httpreq.cpp index e6e442e63..85b70c37b 100644 --- a/src/http/httpreq.cpp +++ b/src/http/httpreq.cpp @@ -99,6 +99,7 @@ HttpReq::HttpReq( ) m_pSSIRuntime = NULL; ::memset( m_commonHeaderLen, 0, (char *)(&m_iLocationOff + 1) - (char *)m_commonHeaderLen ); + m_upgradeProto = UPD_PROTO_NONE; } HttpReq::~HttpReq() @@ -184,6 +185,7 @@ int HttpReq::processHeader() return SC_414; } } + return ret; } else @@ -195,6 +197,8 @@ int HttpReq::processHeader() const HttpVHost * HttpReq::matchVHost() { + if ( !m_pVHostMap ) + return NULL; m_pVHost = m_pVHostMap->getDedicated(); if ( !m_pVHost ) { @@ -231,7 +235,6 @@ int HttpReq::RemoveSpace(const char **pCur, const char *pBEnd) } int HttpReq::processRequestLine() { - static int PrStatus = 0; int result =0; register const char *pCur = m_headerBuf.begin() + m_iReqHeaderBufFinished; register const char *pBEnd = m_headerBuf.end(); @@ -388,7 +391,7 @@ int HttpReq::GetReqURI(const char *pCur, const char *pBEnd ) int HttpReq::GetReqHost(const char* pCur, const char *pBEnd) { - bool bNoHost = false, bHostDone = false; + bool bNoHost = false; if (( *pCur == '/' )||( *pCur == '%' )) bNoHost = true; if(!bNoHost) @@ -498,6 +501,12 @@ int HttpReq::processHeaderLines() pCurHeader->keyLen = SkipSpace( pMark, pLineBegin) - pLineBegin; pCurHeader->valOff = pTemp - m_headerBuf.begin(); pCurHeader->valLen = pTemp1 - pTemp; + + if ( pCurHeader->keyLen == 7 && strncasecmp(pLineBegin, "Upgrade", 7) == 0 && + pCurHeader->valLen == 9 && strncasecmp(pTemp, "websocket", 9) == 0 ) + { + m_upgradeProto = UPD_PROTO_WEBSOCKET; + } } } pLineBegin = pLineEnd + 1; @@ -1570,7 +1579,6 @@ int HttpReq::processPath( const char * pURI, int uriLen, char * pBuf, { int ret; char * p; - struct stat stFP; ret = SC_404; //find the first valid file or directory p = pEnd; @@ -1834,7 +1842,7 @@ int HttpReq::checkPathInfo( const char * pURI, int iURILen, int &pathLen, -int HttpReq::addWWWAuthHeader( AutoBuf &buf ) const +int HttpReq::addWWWAuthHeader( HttpRespHeaders &buf ) const { if ( m_pHTAuth ) return m_pHTAuth->addWWWAuthHeader( buf ); diff --git a/src/http/httpreq.h b/src/http/httpreq.h index e7bd57b86..915bd3cf8 100644 --- a/src/http/httpreq.h +++ b/src/http/httpreq.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -79,6 +79,8 @@ class SSIRuntime; class SSIConfig; class VHostMap; class VMemBuf; +class HttpRespHeaders; + typedef struct { @@ -153,11 +155,13 @@ class HttpReq int m_iMatchedLen; struct stat m_fileStat; int m_iScriptNameLen; - key_value_pair * m_urls; + key_value_pair * m_urls; int m_code; int m_iLocationLen; - LOG4CXX_NS::ILog * m_pILog; + LogTracker * m_pILog; + int m_upgradeProto; + HttpReq( const HttpReq& rhs ) ; void operator=( const HttpReq& rhs ); @@ -246,6 +250,12 @@ class HttpReq HEADER_ERROR_INVALID }; + enum + { + UPD_PROTO_NONE = 0, + UPD_PROTO_WEBSOCKET = 1, + }; + explicit HttpReq(); ~HttpReq(); @@ -254,7 +264,7 @@ class HttpReq void reset(); void reset2(); - void setILog( LOG4CXX_NS::ILog * pILog ){ m_pILog = pILog; } + void setILog( LogTracker * pILog ){ m_pILog = pILog; } LOG4CXX_NS::Logger* getLogger() const { return m_pILog->getLogger(); } const char * getLogId() { return m_pILog->getLogId(); } @@ -291,6 +301,8 @@ class HttpReq int getPathInfoLen() const { return m_iPathInfoLen; } int getQueryStringLen() const { return m_curURL.valLen; } + int isWebsocket() const { return ((UPD_PROTO_WEBSOCKET == m_upgradeProto) ? 1 : 0); } + //request header const char * getHeader( size_t index ) const @@ -381,7 +393,7 @@ class HttpReq void clearLocation() { m_iLocationOff = m_iLocationLen = 0; } - int addWWWAuthHeader( AutoBuf &buf ) const; + int addWWWAuthHeader( HttpRespHeaders &buf ) const; const AuthRequired* getAuthRequired() const { return m_pAuthRequired; } //void matchContext(); diff --git a/src/http/httpresp.cpp b/src/http/httpresp.cpp index 9e76c1d1a..fad500ff0 100644 --- a/src/http/httpresp.cpp +++ b/src/http/httpresp.cpp @@ -41,22 +41,17 @@ int HttpResp::getProtocolLen() const HttpResp::HttpResp() - : m_iLogAccess( 0 ) - , m_iHeaderTotalLen( 0 ) - , m_iSetCookieLen( 0 ) + : m_iHeaderTotalLen( 0 ) + , m_iLogAccess( 0 ) { - reset(); } HttpResp::~HttpResp() { } -void HttpResp::reset() +void HttpResp::reset(RespHeader::FORMAT format) { - if (m_iSetCookieLen && !m_iSetCookieOffset) - m_outputBuf.resize( m_iSetCookieLen ); - else - m_outputBuf.clear(); + m_outputBuf.reset(format); m_iovec.clear(); memset( &m_lEntityLength, 0, (char *)((&m_iHeaderTotalLen) + 1) - (char*)&m_lEntityLength ); @@ -71,80 +66,45 @@ void HttpResp::addLocationHeader( const HttpReq * pReq ) int need = len + 25; if ( *pLocation == '/' ) need += pReq->getHeaderLen( HttpHeader::H_HOST ); - if ( m_outputBuf.available() < need ) - if ( m_outputBuf.grow( need ) ) - return; - m_outputBuf.appendNoCheck( "Location: ", 10 ); + m_outputBuf.add(HttpHeader::H_LOCATION, "Location", 8, "", 0); if ( *pLocation == '/' ) { const char * pHost = pReq->getHeader( HttpHeader::H_HOST ); - m_outputBuf.appendNoCheck( getProtocol(), getProtocolLen() ); - m_outputBuf.appendNoCheck( pHost, pReq->getHeaderLen( HttpHeader::H_HOST ) ); - } - m_outputBuf.appendNoCheck( pLocation, pReq->getLocationLen() ); - m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); -} -/* -#define WWW_AUTH_MAX_LEN 1024 -void HttpResp::addWWWAuthHeader( const HttpReq * pReq ) -{ - int size = WWW_AUTH_MAX_LEN; - const char * pAuthHeader; - char achAuth[WWW_AUTH_MAX_LEN + 1 ]; - pAuthHeader = pReq->getWWWAuthHeader( achAuth, size ); - if ( pAuthHeader ) - { - //if ( ret == WWW_AUTH_MAX_LEN ) - //{ - //FIXME: max size reached - //} - if ( m_outputBuf.available() < size + 10 ) - if ( m_outputBuf.grow( size + 10 ) ) - return; - m_outputBuf.appendNoCheck( pAuthHeader, size ); + m_outputBuf.appendLastVal( "Location", 8, getProtocol(), getProtocolLen() ); + m_outputBuf.appendLastVal( "Location", 8, pHost, pReq->getHeaderLen( HttpHeader::H_HOST ) ); } + m_outputBuf.appendLastVal( "Location", 8, pLocation, pReq->getLocationLen() ); + } -*/ -int HttpResp::safeAppend( const char * pBuf, int len ) +void HttpResp::iovAppend( const char * pBuf, int len ) { - if ( m_outputBuf.available() < len + 10 ) - if ( m_outputBuf.grow( len + 10 ) ) - return -1; - char * p = m_outputBuf.end(); - const char * pSrc = pBuf; - for( int i = 0; i < len ; ++i ) - p[i] = pSrc[i]; - - //memmove( m_outputBuf.end(), pBuf, len ); - m_outputBuf.append( pBuf, len ); - return 0; + m_outputBuf.addNoCheckExptSpdy(pBuf, len ); } void HttpResp::buildCommonHeaders() { - char achDateTime[60]; - char * p = s_sCommonHeaders; - memcpy( p, "Server: ", 8 ); - p += 8; - memcpy( p, HttpServerVersion::getVersion(), - HttpServerVersion::getVersionLen() ); - p += HttpServerVersion::getVersionLen(); - - p += safe_snprintf( p, sizeof( s_sCommonHeaders ) - ( p - s_sCommonHeaders ), - "\r\n" "Date: %s\r\n" "Accept-Ranges: bytes\r\n", - DateTime::getRFCTime( DateTime::s_curTime, achDateTime ) ); - s_iCommonHeaderLen = p - s_sCommonHeaders - RANGE_HEADER_LEN; + for ( int i = 0; i < 3; ++i ) + { + s_CommonHeaders[i].reset((RespHeader::FORMAT)i); + s_CommonHeaders[i].add(HttpHeader::H_SERVER, "Server", 6, HttpServerVersion::getVersion(), HttpServerVersion::getVersionLen()); + updateDateHeader(i + 1); + s_CommonHeaders[i].add(HttpHeader::H_ACCEPT_RANGES, "Accept-Ranges", 13, "bytes", 5); + } } -void HttpResp::updateDateHeader() +void HttpResp::updateDateHeader(int index) { - char * pDateValue = &s_sCommonHeaders[ 10 + 6 + - HttpServerVersion::getVersionLen()]; - DateTime::getRFCTime( DateTime::s_curTime, pDateValue); - *(pDateValue + RFC_1123_TIME_LEN) = '\r'; + char achDateTime[60]; + DateTime::getRFCTime(DateTime::s_curTime, achDateTime); + if (index == 0) + { + for ( int i = 0; i < 3; ++i ) + s_CommonHeaders[i].add(HttpHeader::H_DATE, "Date", 4, achDateTime, strlen(achDateTime)); + } + else + s_CommonHeaders[index - 1].add(HttpHeader::H_DATE, "Date", 4, achDateTime, strlen(achDateTime)); } @@ -153,14 +113,23 @@ void HttpResp::updateDateHeader() void HttpResp::prepareHeaders( const HttpReq * pReq, int rangeHeaderLen ) { - iovAppend( s_sCommonHeaders, s_iCommonHeaderLen + rangeHeaderLen); - if ( pReq->isKeepAlive() ) + HttpRespHeaders *pRespHeaders = NULL; + int idFormat = m_outputBuf.getFormat(); + pRespHeaders = &s_CommonHeaders[idFormat]; + + pRespHeaders->getHeaders(&m_iovec); + m_outputBuf.setUnmanagedHeadersCount(pRespHeaders->getCount()); + + if ( m_outputBuf.getFormat() == RespHeader::REGULAR ) { - if ( pReq->getVersion() != HTTP_1_1 ) - iovAppend( s_sKeepAliveHeader, KEEP_ALIVE_HEADER_LEN ); + if ( pReq->isKeepAlive() ) + { + if ( pReq->getVersion() != HTTP_1_1 ) + iovAppend( s_sKeepAliveHeader, KEEP_ALIVE_HEADER_LEN ); + } + else + iovAppend( s_sConnCloseHeader, sizeof( s_sConnCloseHeader ) - 1 ); } - else - iovAppend( s_sConnCloseHeader, sizeof( s_sConnCloseHeader ) - 1 ); if ( pReq->getAuthRequired() ) pReq->addWWWAuthHeader( m_outputBuf ); if ( pReq->getLocationOff() ) @@ -170,50 +139,39 @@ void HttpResp::prepareHeaders( const HttpReq * pReq, int rangeHeaderLen ) const AutoBuf * pExtraHeaders = pReq->getExtraHeaders(); if ( pExtraHeaders ) { - m_outputBuf.append( pExtraHeaders->begin(), pExtraHeaders->size() ); + m_outputBuf.addNoCheckExptSpdy( pExtraHeaders->begin(), pExtraHeaders->size() ); } } void HttpResp::appendContentLenHeader() { - if ( m_outputBuf.available() < 70 ) - { - if ( m_outputBuf.grow( 70 ) ) - return; - } - int n = safe_snprintf( m_outputBuf.end(), 60, - "Content-Length: %ld\r\n", m_lEntityLength ); - m_outputBuf.used( n ); + static char sLength[44] = {0}; + int n = safe_snprintf( sLength, 43, "%ld", m_lEntityLength ); + m_outputBuf.add(HttpHeader::H_CONTENT_LENGTH, "Content-Length", + 14, sLength, n); } - -int HttpResp::appendHeader( const char * pName, int nameLen, - const char * pValue, int valLen ) +void HttpResp::finalizeHeader( int ver, int code) { - if ( m_outputBuf.available() < nameLen + valLen + 6 ) - { - if ( m_outputBuf.grow( nameLen + valLen + 6 ) == -1 ) - return -1; - } - m_outputBuf.appendNoCheck( pName, nameLen ); - m_outputBuf.append( ':' ); - m_outputBuf.append( ' ' ); - m_outputBuf.appendNoCheck( pValue, valLen ); - m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); - return 0; + //addStatusLine will add HTTP/1.1 to front of m_iovec when regular format + // will add version: HTTP/1.1 status: 2XX (etc) to m_outputBuf when SPDY format + // *** Be careful about this difference *** + m_outputBuf.addStatusLine(&m_iovec, ver, code); + m_outputBuf.endHeader(); + m_outputBuf.getHeaders(&m_iovec); + + + + int bufSize = m_iovec.bytes(); + m_iHeaderLeft += bufSize; + m_iHeaderTotalLen = m_iHeaderLeft; } - -int HttpResp::appendHeaderLine( const char * pLineBegin, const char * pLineEnd ) + +int HttpResp::appendHeader( const char * pName, int nameLen, + const char * pValue, int valLen ) { - if ( m_outputBuf.available() < pLineEnd - pLineBegin + 4 ) - { - if ( m_outputBuf.grow( pLineEnd - pLineBegin + 4 ) == -1 ) - return -1; - } - m_outputBuf.appendNoCheck( pLineBegin, pLineEnd - pLineBegin ); - m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); + //FIXME: -1 all right? + m_outputBuf.add(-1, pName, nameLen, pValue, valLen, RespHeader::APPEND); return 0; } @@ -227,74 +185,36 @@ int HttpResp::appendHeaderLine( const char * pLineBegin, const char * pLineEnd ) int HttpResp::appendLastMod( long tmMod ) { - if ( m_outputBuf.available() < RFC_1123_TIME_LEN + 21 ) - { - if ( m_outputBuf.grow( RFC_1123_TIME_LEN + 21 ) == -1 ) - return -1; - } - m_outputBuf.append( "Last-Modified: ", 15 ); - DateTime::getRFCTime( tmMod, m_outputBuf.end() ); - m_outputBuf.used( RFC_1123_TIME_LEN ); - m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); + static char sTimeBuf[RFC_1123_TIME_LEN + 1] = {0}; + DateTime::getRFCTime( tmMod, sTimeBuf ); + m_outputBuf.add(HttpHeader::H_LAST_MODIFIED, "Last-Modified", 13, + sTimeBuf, RFC_1123_TIME_LEN ); return 0; } + int HttpResp::addCookie( const char * pName, const char * pVal, const char * path, const char * domain, int expires, int secure, int httponly ) { if ( !pName || !pVal || !domain ) return -1; - if ( !m_iSetCookieLen ) - m_outputBuf.clear(); - int len = strlen( pName )+ strlen( pVal ) + strlen( domain ) + - path? strlen( path ): 1; - if ( m_outputBuf.available() < len + 150 ) - { - if ( m_outputBuf.grow( len + 150 ) == -1 ) - return -1; - } - - int n = snprintf( m_outputBuf.end(), m_outputBuf.available(), "Set-Cookie: %s=%s; path=%s; domain=%s", + + char sBuf[8192] = {0}; + snprintf( sBuf, 8191, "%s=%s; path=%s; domain=%s", pName, pVal, path? path:"/", domain ); - m_outputBuf.used( n ); if ( expires ) { - m_outputBuf.append( "; expires=" ); + strcat(sBuf, "; expires=" ); long t = DateTime::s_curTime + expires * 60; - DateTime::getRFCTime( t, m_outputBuf.end() ); - m_outputBuf.used( RFC_1123_TIME_LEN ); + DateTime::getRFCTime( t, sBuf + strlen(sBuf) ); } if ( secure ) - m_outputBuf.append( "; secure" ); + strcat(sBuf, "; secure" ); if ( httponly ) - m_outputBuf.append( "; HttpOnly" ); - m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); - m_iSetCookieLen = m_outputBuf.size(); + strcat(sBuf, "; HttpOnly" ); + + m_outputBuf.add(HttpHeader::H_SET_COOKIE, "Set-Cookie", 10, sBuf, strlen(sBuf), RespHeader::APPEND); return 0; } -void HttpResp::setCookieHeaderLen( int len ) -{ - if ( !m_iSetCookieLen ) - { - m_iSetCookieOffset = m_outputBuf.size(); - m_iSetCookieLen = len; - return; - } - int moveBytes = m_outputBuf.size() - ( m_iSetCookieOffset + m_iSetCookieLen ); - - if ( moveBytes > 0 ) - { - char achBuf[65535]; - assert( moveBytes < 65535 ); - memmove( achBuf, m_outputBuf.end() - moveBytes, moveBytes ); - memmove( m_outputBuf.end() - m_iSetCookieLen, - m_outputBuf.getPointer( m_iSetCookieOffset ), m_iSetCookieLen ); - memmove( m_outputBuf.getPointer( m_iSetCookieOffset ), achBuf, moveBytes ); - m_iSetCookieOffset = m_outputBuf.size() - m_iSetCookieLen ; - } - m_iSetCookieLen += len; -} diff --git a/src/http/httpresp.h b/src/http/httpresp.h index feb85b80b..b70b95d70 100644 --- a/src/http/httpresp.h +++ b/src/http/httpresp.h @@ -22,6 +22,7 @@ #include #include #include +#include #define RANGE_HEADER_LEN 22 @@ -30,20 +31,18 @@ class HttpReq; class HttpResp { private: - static char s_sCommonHeaders[128]; - static int s_iCommonHeaderLen; + static HttpRespHeaders s_CommonHeaders[3]; static char s_sKeepAliveHeader[25]; static char s_sConnCloseHeader[20]; static char s_chunked[29]; static char s_sGzipEncodingHeader[48]; IOVec m_iovec; - AutoBuf m_outputBuf; + HttpRespHeaders m_outputBuf; + long m_lEntityLength; long m_lEntityFinished; - int m_iContentTypeStarts; - int m_iContentTypeLen; int m_iHeaderLeft; int m_iSetCookieOffset; int m_iSetCookieLen; @@ -60,7 +59,7 @@ class HttpResp explicit HttpResp(); ~HttpResp(); - void reset(); + void reset(RespHeader::FORMAT format); // { // m_outputBuf.clear(); // m_iovec.clear(); @@ -76,12 +75,8 @@ class HttpResp void prepareHeaders( const HttpReq * pReq, int rangeHeaderLen = 0 ); void appendContentLenHeader(); - int safeAppend( const char * pBuf, int len ); - - void endHeader() { m_outputBuf.append( '\r' ); - m_outputBuf.append( '\n' ); } - AutoBuf& getOutputBuf() + HttpRespHeaders& getHeaders() { return m_outputBuf; } void setContentLen( long len ) { m_lEntityLength = len; } @@ -99,7 +94,7 @@ class HttpResp { return (m_lEntityLength == -1); } static void buildCommonHeaders(); - static void updateDateHeader(); + static void updateDateHeader(int index = 0); //0 means all, and 1, 2 and 3 mean the (index -1) one const char * getProtocol() const; int getProtocolLen() const; @@ -107,25 +102,14 @@ class HttpResp void setSSL( int ssl ) { m_iSSL = (ssl != 0 ); } - void finalizeHeader( int ver, int code) - { - const StatusLineString& statusLine = - HttpStatusLine::getStatusLine( ver, code ); - m_iovec.push_front( statusLine.get(), statusLine.getLen() ); - int bufSize = m_outputBuf.size(); - m_iHeaderLeft += statusLine.getLen() + bufSize; - if ( bufSize ) - m_iovec.append( m_outputBuf.begin(), bufSize ); - m_iHeaderTotalLen = m_iHeaderLeft; - } + void finalizeHeader( int ver, int code); + IOVec& getIov() { return m_iovec; } - void iovAppend( const char * pBuf, int len ) - { - safeAppend( pBuf, len ); - } + void iovAppend( const char * pBuf, int len ); void appendExtra( const char * pBuf, int len ) - { m_iovec.append( pBuf, len ); + { //m_iovec.append( pBuf, len ); + m_outputBuf.addNoCheckExptSpdy(pBuf, len ); m_iHeaderTotalLen += len; m_iHeaderLeft += len; } void addGzipEncodingHeader() @@ -138,33 +122,19 @@ class HttpResp iovAppend( s_chunked, sizeof( s_chunked )- 1 ); } - int appendHeaderLine( const char * pLineBegin, const char * pLineEnd ); - int& getHeaderLeft() { return m_iHeaderLeft; } void setHeaderLeft( int len ) { m_iHeaderLeft = len; } long getTotalLen() const { return m_lEntityFinished + m_iHeaderTotalLen; } int getHeaderSent() const { return m_iHeaderTotalLen - m_iHeaderLeft; } int getHeaderTotal() const { return m_iHeaderTotalLen; } - const char * getContentTypeHeader(int &len ) - { - if ( !m_iContentTypeStarts ) - return NULL; - len = m_iContentTypeLen; - return m_outputBuf.begin() + m_iContentTypeStarts; - } - void setContentTypeHeaderInfo( int offset, int len ) - { - m_iContentTypeStarts = offset; - m_iContentTypeLen = len; - } + const char * getContentTypeHeader(int &len ) { return m_outputBuf.getContentTypeHeader(len); } + int appendLastMod( long tmMod ); int addCookie( const char * pName, const char * pVal, const char * path, const char * domain, int expires, int secure, int httponly ); - void setCookieHeaderLen( int len ); - void clearSetCookieLen() - { m_iSetCookieOffset = 0; m_iSetCookieLen = 0; } + }; #endif diff --git a/src/http/httprespheaders.cpp b/src/http/httprespheaders.cpp new file mode 100644 index 000000000..da8efc351 --- /dev/null +++ b/src/http/httprespheaders.cpp @@ -0,0 +1,472 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "http/httprespheaders.h" +#include +#include +#include +#include + +/******************************************************************************* + * Something about kvapir + * For a regular foramt header, keyOff is the real offset of the key/name + * valOff is the real offset of the value + * + * For a SPDY format header, keyOff is the first position of the section of key/name + * Since the key/name section is short length (2 bytes) + key, + * though keyOff + 2 equals to real offset of the key/name + * And the same way, valOff + 2 is the real offset of the value + * + * ****************************************************************************/ + +HttpRespHeaders::HttpRespHeaders() +{ + m_sKVPair = ""; + incKVPairs(20); //init 20 kvpair spaces + reset(); +} + +void HttpRespHeaders::reset(RespHeader::FORMAT format) +{ + m_headerFormat = format; + m_hasHole = 0; + m_iHeaderCount = 0; + m_buf.clear(); + memset(m_KVPairindex, 0xFF, HttpHeader::H_HEADER_END); + memset(m_sKVPair.buf(), 0, m_sKVPair.len()); + m_hLastHeaderKVPairIndex = -1; + m_iExtraBufOff = -1; + m_iExtraBufLen = 0; + m_iUnmanagedHeadersCount = 0; +} + +void HttpRespHeaders::incKVPairs(int num) +{ + int size = m_sKVPair.len() + sizeof(key_value_pair) * num; + m_sKVPair.resizeBuf(size); + m_sKVPair.setLen(size); + + size = sizeof(key_value_pair) * num; + char *temp = m_sKVPair.buf() + m_sKVPair.len() - size; + memset(temp, 0, size); +} + +inline key_value_pair * HttpRespHeaders::getKVPair(int index) +{ + key_value_pair *pKVPair = (key_value_pair *) (m_sKVPair.buf() + index * sizeof(key_value_pair)); + return pKVPair; +} + +//Replace the value with new value in pKv, in this case must have enough space +void HttpRespHeaders::replaceHeader(key_value_pair *pKv, const char * pVal, unsigned int valLen) +{ + char *pOldVal = getVal(pKv); + memcpy( pOldVal, pVal, valLen ); + memset( pOldVal + valLen, ' ', pKv->valLen - valLen); +} + +inline void appendLowerCase(AutoBuf& buf , const char *str, unsigned int len) +{ + const char *pEnd = str + len; + while (str < pEnd) + buf.append( *str ++ | 0x20); +} + +inline void appendNetInt(AutoBuf &buf, int n, int bytesNum) +{ + assert( bytesNum == 2 || bytesNum == 4); + char *p = buf.end() - 1; + buf.used(bytesNum); + while( bytesNum ) + { + p[bytesNum--] = (char)(n & 0xFF); + n >>= 8; + } +} + +int HttpRespHeaders::appendHeader(key_value_pair *pKv, const char * pName, unsigned int nameLen, const char * pVal, unsigned int valLen) +{ + /******************************************************************* + * About Append in regular header + * ie. set-cookie: "123" will append set-cookie: "4567" + * At beginning, key: set-cookie, Val: "123" + * End, key: set-cookie, Val: "123\r\nset-cookie: 4567 " + * In this way, we will store set-cookie in one place of kvlist + ******************************************************************/ + + //Will insert a "\0" between new value and old value when spdy + if ( m_buf.available() < (int)(pKv->valLen + nameLen * 2 + valLen + 8 + 2) ) + { + if ( m_buf.grow( pKv->valLen + nameLen * 2 + valLen + 8 + 2 ) ) + return -1; + } + + pKv->keyOff = m_buf.size(); + pKv->keyLen = nameLen; + + if (m_headerFormat == RespHeader::REGULAR) + { + m_buf.appendNoCheck(pName, nameLen); + m_buf.appendNoCheck(": ", 2); + if (pKv->valLen > 0) + { + //include 2 more chars, they ARE \r\n + m_buf.appendNoCheck(m_buf.begin() + pKv->valOff, pKv->valLen + 2); + m_buf.appendNoCheck(pName, nameLen); + m_buf.appendNoCheck(": ", 2); + pKv->valLen += 2 + nameLen + 2; + } + m_buf.appendNoCheck(pVal, valLen); + m_buf.appendNoCheck("\r\n", 2); + + pKv->valLen += valLen; + } + else + { + appendNetInt(m_buf, nameLen, ((m_headerFormat == RespHeader::SPDY2) ? 2 : 4 )); + appendLowerCase(m_buf , pName, nameLen); + + int tmpValLen = ((pKv->valLen > 0)?(pKv->valLen + 1):(0)) + valLen; + appendNetInt(m_buf, tmpValLen, ((m_headerFormat == RespHeader::SPDY2) ? 2 : 4 )); + + if (pKv->valLen > 0) + { + m_buf.appendNoCheck(m_buf.begin() + pKv->valOff + + ((m_headerFormat == RespHeader::SPDY2) ? 2 : 4 ), pKv->valLen); + m_buf.append('\0'); + } + m_buf.appendNoCheck(pVal, valLen); + + pKv->valLen = tmpValLen; + } + pKv->valOff = pKv->keyOff + nameLen + 2 + (( m_headerFormat == RespHeader::SPDY3) ? 2 : 0 ); + return 0; +} + +//replace_or_append: 0 replace,1 append +int HttpRespHeaders::add( int headerIndex, const char * pName, unsigned int nameLen, const char * pVal, unsigned int valLen, RespHeader::ADD_METHOD method ) +{ + assert (headerIndex < HttpHeader::H_HEADER_END); + assert ( nameLen > 0 ); + + int count = m_iHeaderCount; + int kvOrderNum = count; + key_value_pair *pKv = NULL; + + //-1 menas unkonw, check if it is already in our index list + //if we do know it is NOT in, we can bypass this for-loop step + if ( headerIndex == -1 ) + { + int ret = getHeaderIndex(pName, nameLen); + if ( ret != -1) + kvOrderNum = ret; + } + else + { + if (m_KVPairindex[headerIndex] != 0xFF) + kvOrderNum = m_KVPairindex[headerIndex]; + else + { + m_KVPairindex[headerIndex] = kvOrderNum; + } + } + + if ( kvOrderNum == count ) + { + //Add a new header not inside before + if (getFreeSpaceCount() == 0) + incKVPairs(10); + ++m_iHeaderCount; + } + + pKv = getKVPair(kvOrderNum); + + //enough space for replace, use the same keyoff, and update valoff, add padding, make it is the same leangth as before + if (method == RespHeader::REPLACE && pKv->keyLen + pKv->valLen >= (int) (nameLen + valLen) ) + { + assert ( pKv->keyLen == (int)nameLen ); + assert ( strncasecmp(getName(pKv), pName, nameLen) ==0 ); + replaceHeader(pKv, pVal, valLen); + return 0; + } + //Newly add will also be treated as append + else + { + m_hLastHeaderKVPairIndex = kvOrderNum; + + //Under append situation, if has existing key and valLen > 0, then makes a hole + if (pKv->valLen > 0) + { + assert(pKv->keyLen > 0); + m_hasHole = 1; + } + + return appendHeader(pKv, pName, nameLen, pVal, valLen); + } +} + +//This will only append value to the last item +int HttpRespHeaders::appendLastVal(const char * pName, int nameLen, const char * pVal, int valLen) +{ + if (m_hLastHeaderKVPairIndex == -1 && valLen <= 0) + return -1; + + assert( m_hLastHeaderKVPairIndex < m_iHeaderCount ); + key_value_pair *pKv = getKVPair(m_hLastHeaderKVPairIndex); + + //check if it is the end + if (m_buf.size() != pKv->valOff + pKv->valLen + 2 + ((m_headerFormat == RespHeader::SPDY3) ? 2 : 0)) + return -1; + + //check if the name match + if (pKv->keyLen != nameLen || strncasecmp(pName, getName(pKv), nameLen) != 0) + return -1; + + if ( m_buf.available() < valLen) + { + if ( m_buf.grow( valLen ) ) + return -1; + } + + //Only update the valLen of the kvpair + pKv->valLen += valLen; + if (m_headerFormat == RespHeader::REGULAR) + { + m_buf.used( -2 );//move back two char, to replace the \r\n at the end + m_buf.appendNoCheck(pVal, valLen); + m_buf.appendNoCheck("\r\n", 2); + } + else if (m_headerFormat == RespHeader::SPDY2) + { + m_buf.appendNoCheck(pVal, valLen); + short *valLenRef = (short *)(m_buf.begin() + pKv->valOff); + *valLenRef = htons(pKv->valLen); + } + else + { + m_buf.appendNoCheck(pVal, valLen); + int32_t *valLenRef = (int32_t *)(m_buf.begin() + pKv->valOff); + *valLenRef = htonl(pKv->valLen); + } + + return 0; +} + +void HttpRespHeaders::delAndMove(int kvOrderNum) +{ + if (kvOrderNum == -1) + return; + + key_value_pair *pKvLastPos = getKVPair(m_iHeaderCount- 1); + if (kvOrderNum != m_iHeaderCount- 1) + { + //move the last pos memory to the deleled pos + key_value_pair *pKv = getKVPair(kvOrderNum); + memcpy(pKv, pKvLastPos, sizeof(key_value_pair)); + } + //need to empty this section for later using won't mess up + memset(pKvLastPos, 0, sizeof(key_value_pair)); + + for (int i=0; i 0); + int kvOrderNum = getHeaderIndex(pName, nameLen);; + delAndMove(kvOrderNum); + return 0; +} + +//del() will make some {0,0,0,0} kvpair in the list and make hole +int HttpRespHeaders::del( int headerIndex ) +{ + if (headerIndex < 0) + return -1; + + if (m_KVPairindex[headerIndex] != 0xFF) + { + delAndMove(m_KVPairindex[headerIndex]); + m_KVPairindex[headerIndex] = 0xFF; + } + return 0; +} + +void HttpRespHeaders::getHeaders(IOVec *io) +{ + if (m_hasHole == 0) + { + if (m_buf.size() > 0) + io->append(m_buf.begin(), m_buf.size()); + } + else + { + for (int i=0; ikeyLen > 0); + if (m_headerFormat != RespHeader::SPDY3) + io->appendCombine(m_buf.begin() + pKv->keyOff, pKv->keyLen + pKv->valLen + 4); + else + io->appendCombine(m_buf.begin() + pKv->keyOff, pKv->keyLen + pKv->valLen + 8); + } + + //deal with the extra buffer "...................\r\n\r\n" + if ( m_headerFormat == RespHeader::REGULAR && m_iExtraBufOff != -1) + io->appendCombine(m_buf.begin() + m_iExtraBufOff, m_iExtraBufLen); + } +} + +void HttpRespHeaders::addStatusLine(IOVec *io, int ver, int code) +{ + const StatusLineString& statusLine = HttpStatusLine::getStatusLine( ver, code ); + + if (m_headerFormat == RespHeader::REGULAR) + io->push_front( statusLine.get(), statusLine.getLen() ); + else if (m_headerFormat == RespHeader::SPDY2) + { + add(-1, "status", 6, statusLine.get() + 9, 3); + add(-1, "version", 7, statusLine.get(), 8); + } + else + { + add(-1, ":status", 7, statusLine.get() + 9, 3); + add(-1, ":version", 8, statusLine.get(), 8); + } +} + +char *HttpRespHeaders::getContentTypeHeader(int &len) +{ + int index = m_KVPairindex[HttpHeader::H_CONTENT_TYPE]; + if (index == 0xFF) + { + len = -1; + return NULL; + } + + key_value_pair *pKv = getKVPair(index); + len = pKv->valLen; + return getVal(pKv); +} + +void HttpRespHeaders::endHeader() +{ + if (m_headerFormat == RespHeader::REGULAR) + { + if (m_iExtraBufOff == -1) + m_iExtraBufOff = m_buf.size(); + + m_buf.append("\r\n", 2); + m_iExtraBufLen += 2; + } +} + + +//The below calling will not maintance the kvpaire when regular case +void HttpRespHeaders::addNoCheckExptSpdy(const char * pStr, int len ) +{ + if (m_headerFormat == RespHeader::REGULAR) + { + if (m_iExtraBufOff == -1) + m_iExtraBufOff = m_buf.size(); + + m_buf.append(pStr, len); + m_iExtraBufLen += len; + } + else + { + //When SPDY format, we need to parse it and add one by one + const char *pName = NULL; + int nameLen = 0; + const char *pVal = NULL; + int valLen = 0; + + const char *pBEnd = pStr + len; + const char *pMark = NULL; + const char *pLineEnd= NULL; + const char* pLineBegin = pStr; + + while((pLineEnd = ( const char *)memchr(pLineBegin, '\n', pBEnd - pLineBegin )) != NULL) + { + pMark = ( const char *)memchr(pLineBegin, ':', pLineEnd - pLineBegin); + if(pMark != NULL) + { + pName = pLineBegin; + nameLen = pMark - pLineBegin; //Should - 1 to remove the ':' position + pVal = pMark + 2; + if (*pVal == ' ') + ++ pVal; + valLen = pLineEnd - pVal; + if (*(pLineEnd - 1) == '\r') + -- valLen; + + //This way, all the value use APPEND as default + add(-1, pName, nameLen, pVal, valLen, RespHeader::APPEND); + } + + pLineBegin = pLineEnd + 1; + if (pBEnd <= pLineBegin + 1) + break; + } + } +} + +int HttpRespHeaders::getHeaderIndex(const char *pName, unsigned int nameLen) +{ + int index = -1; + key_value_pair *pKv = NULL; + + for (int i=0; ikeyLen == (int)nameLen && + strncasecmp(pName, getName(pKv), nameLen) == 0) + { + index = i; + break; + } + } + + return index; +} + + +int HttpRespHeaders::getHeader(const char *pName, int nameLen, char **pVal, int &valLen) +{ + int kvOrderNum = getHeaderIndex(pName, nameLen); + if ( -1 != kvOrderNum ) + { + key_value_pair *pKv = getKVPair(kvOrderNum); + *pVal = getVal(pKv); + valLen = pKv->valLen; + return 0; + } + else + return -1; +} diff --git a/src/http/httprespheaders.h b/src/http/httprespheaders.h new file mode 100644 index 000000000..e085ad41e --- /dev/null +++ b/src/http/httprespheaders.h @@ -0,0 +1,101 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef HTTPRESPHEADERS_H +#define HTTPRESPHEADERS_H + +#include +#include +#include +#include + +namespace RespHeader { + enum FORMAT { + REGULAR = 0, + SPDY2, + SPDY3, + }; + + enum ADD_METHOD { + REPLACE = 0, + APPEND, + }; +}; + +class HttpRespHeaders +{ +public: + HttpRespHeaders(); + ~HttpRespHeaders() {}; + + void reset(RespHeader::FORMAT format = RespHeader::REGULAR); + + int add( int headerIndex, const char * pName, unsigned int nameLen, const char * pVal, unsigned int valLen, RespHeader::ADD_METHOD method = RespHeader::REPLACE ); + int appendLastVal( const char * pName, int nameLen, const char * pVal, int valLen ); + + void addNoCheckExptSpdy( const char * pStr, int len ); + + + //Special case + void addStatusLine( IOVec *io, int ver, int code ); + + int del( const char * pName, int nameLen ); + int del( int headerIndex ); + + void getHeaders( IOVec *io ); + int getCount() const { return m_iHeaderCount; } + int getTotalCount() const { return m_iUnmanagedHeadersCount + m_iHeaderCount; }; + RespHeader::FORMAT getFormat() const { return m_headerFormat; }; + void endHeader(); + + char *getContentTypeHeader(int &len); + void setUnmanagedHeadersCount(int n) { m_iUnmanagedHeadersCount = n; }; + + int getHeader(const char *pName, int nameLen, char **pVal, int &valLen); + + +private: + AutoBuf m_buf; + unsigned char m_KVPairindex[HttpHeader::H_HEADER_END]; + AutoStr2 m_sKVPair; + int m_hasHole; + RespHeader::FORMAT m_headerFormat; + int m_iHeaderCount; + int m_hLastHeaderKVPairIndex; + int m_iExtraBufOff; + int m_iExtraBufLen; + int m_iUnmanagedHeadersCount; + +private: + + int getFreeSpaceCount() const { return m_sKVPair.len() / sizeof(key_value_pair) - m_iHeaderCount; }; + void incKVPairs(int num); + key_value_pair *getKVPair(int index); + char * getHeaderStr(int offset) { return m_buf.begin() + offset + (int)m_headerFormat * 2; } + char * getName(key_value_pair *pKv) { return getHeaderStr(pKv->keyOff); } + char * getVal(key_value_pair *pKv) { return getHeaderStr(pKv->valOff); } + + void delAndMove(int kvOrderNum); + void replaceHeader(key_value_pair *pKv, const char * pVal, unsigned int valLen); + int appendHeader(key_value_pair *pKv, const char * pName, unsigned int nameLen, const char * pVal, unsigned int valLen); + int getHeaderIndex(const char *pName, unsigned int nameLen); + + HttpRespHeaders(const HttpRespHeaders& other) {}; + +}; + +#endif // HTTPRESPHEADERS_H diff --git a/src/http/httpserverconfig.cpp b/src/http/httpserverconfig.cpp index 6b02930d2..503ef3434 100644 --- a/src/http/httpserverconfig.cpp +++ b/src/http/httpserverconfig.cpp @@ -26,8 +26,8 @@ HttpServerConfig::HttpServerConfig() : m_iMaxURLLen( DEFAULT_URL_LEN + 20 ) , m_iMaxHeaderBufLen( DEFAULT_REQ_HEADER_BUF_LEN ) , m_iMaxReqBodyLen( DEFAULT_REQ_BODY_LEN ) - , m_iMaxDynRespHeaderLen( DEFAULT_DYN_RESP_HEADER_LEN ) , m_iMaxDynRespLen( DEFAULT_DYN_RESP_LEN ) + , m_iMaxDynRespHeaderLen( DEFAULT_DYN_RESP_HEADER_LEN ) , m_iMaxKeepAliveRequests( 100 ) , m_iSmartKeepAlive( 0 ) , m_iUseSendfile( 0 ) @@ -71,13 +71,13 @@ void HttpServerConfig::setMaxHeaderBufLen( int len ) m_iMaxHeaderBufLen = len ; } -void HttpServerConfig::setMaxReqBodyLen( int len ) +void HttpServerConfig::setMaxReqBodyLen( int64_t len ) { if (( len >= 4096 )&&( len <= MAX_REQ_BODY_LEN )) m_iMaxReqBodyLen = len ; } -void HttpServerConfig::setMaxDynRespLen( int len ) +void HttpServerConfig::setMaxDynRespLen( int64_t len ) { if (( len >= 4096 )&&( len <= MAX_DYN_RESP_LEN )) m_iMaxDynRespLen = len ; diff --git a/src/http/httpserverconfig.h b/src/http/httpserverconfig.h index 253e2d65b..4b76a71ac 100644 --- a/src/http/httpserverconfig.h +++ b/src/http/httpserverconfig.h @@ -29,9 +29,9 @@ class HttpServerConfig int32_t m_iMaxURLLen; int32_t m_iMaxHeaderBufLen; - int32_t m_iMaxReqBodyLen; + int64_t m_iMaxReqBodyLen; + int64_t m_iMaxDynRespLen; int32_t m_iMaxDynRespHeaderLen; - int32_t m_iMaxDynRespLen; int16_t m_iMaxKeepAliveRequests; int8_t m_iSmartKeepAlive; int8_t m_iUseSendfile; @@ -99,8 +99,8 @@ class HttpServerConfig void setMaxURLLen( int len ); void setMaxHeaderBufLen( int len ); - void setMaxReqBodyLen( int len ); - void setMaxDynRespLen( int len ); + void setMaxReqBodyLen( int64_t len ); + void setMaxDynRespLen( int64_t len ); void setMaxDynRespHeaderLen( int len ); int32_t getMaxURLLen() const { return m_iMaxURLLen; } diff --git a/src/http/httpserverversion.cpp b/src/http/httpserverversion.cpp index 3f88e845d..d3595268b 100644 --- a/src/http/httpserverversion.cpp +++ b/src/http/httpserverversion.cpp @@ -17,7 +17,8 @@ *****************************************************************************/ #include "httpserverversion.h" -const char HttpServerVersion::s_pVersion[] = "LiteSpeed Open"; + +const char HttpServerVersion::s_pVersion[] = "LiteSpeed/" PACKAGE_VERSION " Open"; int HttpServerVersion::s_iVersionLen = 9; //sizeof( s_pVersion ) - 1; diff --git a/src/http/httpserverversion.h b/src/http/httpserverversion.h index 6984224b1..9279dc5e6 100644 --- a/src/http/httpserverversion.h +++ b/src/http/httpserverversion.h @@ -18,9 +18,7 @@ #ifndef HTTPSERVERVERSION_H #define HTTPSERVERVERSION_H - - -#define VERSION "1.0" +#include class HttpServerVersion { diff --git a/src/http/httpstatuscode.cpp b/src/http/httpstatuscode.cpp index 055f69bf9..32e4d867c 100644 --- a/src/http/httpstatuscode.cpp +++ b/src/http/httpstatuscode.cpp @@ -33,7 +33,6 @@ StatusCode::StatusCode( int code, const char * pStatus, status_size = strlen( pStatus ); if ( message ) { - m_message = message; char achBuf[2048]; char * p = achBuf; char * pEnd = p + 2048; @@ -51,33 +50,31 @@ StatusCode::StatusCode( int code, const char * pStatus, p += safe_snprintf( p, pEnd -p, "\n" ); m_iBodySize = p - achBuf; - m_pHtml = (char *)malloc( m_iBodySize + 160 ); - if ( !m_pHtml ) + m_pHeaderBody = (char *)malloc( m_iBodySize + 160 ); + if ( !m_pHeaderBody ) m_iBodySize =0; else { int n; if ( code >= SC_307 ) { - n = safe_snprintf( m_pHtml, 159, + n = safe_snprintf( m_pHeaderBody, 159, "Cache-Control: private, no-cache, max-age=0\r\n" "Pragma: no-cache\r\n" "Content-Type: text/html\r\n" - "Content-Length: %d\r\n" - "\r\n", + "Content-Length: %d\r\n", m_iBodySize ); } else { - n = safe_snprintf( m_pHtml, 79, + n = safe_snprintf( m_pHeaderBody, 79, "Content-Type: text/html\r\n" - "Content-Length: %d\r\n" - "\r\n", + "Content-Length: %d\r\n", m_iBodySize ); } - memcpy( m_pHtml + n, achBuf, m_iBodySize + 1 ); - m_iTotalSize = m_iBodySize + n; + m_iHeaderSize = n; + memcpy( m_pHeaderBody + n, achBuf, m_iBodySize + 1 ); } } } @@ -85,8 +82,8 @@ StatusCode::StatusCode( int code, const char * pStatus, StatusCode::~StatusCode() { - if ( m_pHtml ) - free( m_pHtml ); + if ( m_pHeaderBody ) + free( m_pHeaderBody ); } int HttpStatusCode::codeToIndex( const char * code ) diff --git a/src/http/httpstatuscode.h b/src/http/httpstatuscode.h index 83adf0b45..c0c069ecb 100644 --- a/src/http/httpstatuscode.h +++ b/src/http/httpstatuscode.h @@ -21,6 +21,7 @@ #include +#include enum { @@ -89,13 +90,14 @@ enum class StatusCode { -public: + friend class HttpStatusCode; + const char * m_status; int status_size; - const char * m_message; - char * m_pHtml; - int m_iTotalSize; + char * m_pHeaderBody; + int m_iHeaderSize; int m_iBodySize; +public: StatusCode( int code, const char * pStatus, const char * body ); ~StatusCode(); @@ -181,13 +183,9 @@ class HttpStatusCode { return getCodeString( m_iCode ); } - const char * getMessage() const - { - return getMessage( m_iCode ); - } const char * getHtml() const { - return getHtml( m_iCode ); + return getRealHtml( m_iCode ); } static const char * getCodeString( http_sc_t code ) @@ -198,28 +196,23 @@ class HttpStatusCode { return s_pSC[code].status_size; } - static const char * getHtml( http_sc_t code ) + static const char * getHeaders( http_sc_t code ) { - return s_pSC[code].m_pHtml; + return s_pSC[code].m_pHeaderBody; + } + static int getHeadersLen( http_sc_t code ) + { + return s_pSC[code].m_iHeaderSize; } static const char * getRealHtml( http_sc_t code ) { - return (s_pSC[code].m_pHtml)?s_pSC[code].m_pHtml + - s_pSC[code].m_iTotalSize - s_pSC[code].m_iBodySize - : s_pSC[code].m_pHtml; + return (s_pSC[code].m_pHeaderBody)?s_pSC[code].m_pHeaderBody + + s_pSC[code].m_iHeaderSize : NULL; } static int getBodyLen( http_sc_t code ) { return s_pSC[code].m_iBodySize; } - static int getTotalLen( http_sc_t code ) - { - return s_pSC[code].m_iTotalSize; - } - static const char * getMessage( http_sc_t code ) - { - return s_pSC[code].m_message; - } static int codeToIndex( const char * code ); diff --git a/src/http/httputil.cpp b/src/http/httputil.cpp index 555fd3073..3a95a140f 100644 --- a/src/http/httputil.cpp +++ b/src/http/httputil.cpp @@ -334,8 +334,6 @@ int HttpUtil::escapeHtml(const char *pSrc, const char * pSrcEnd, char * pDest, i { char * pBegin = pDest; char * pEnd = pDest + n - 6; - int i, j; - char *x; char ch; while( (pSrc < pSrcEnd )&&(ch = *pSrc)&&( pDest < pEnd ) ) { diff --git a/src/http/iptogeo.cpp b/src/http/iptogeo.cpp index 7e05d7aa4..353652587 100644 --- a/src/http/iptogeo.cpp +++ b/src/http/iptogeo.cpp @@ -75,7 +75,7 @@ const char * GeoInfo::getGeoEnv( const char * pEnvName ) if ( strcasecmp( pEnvName, "CODE" ) == 0 ) { - if ( (m_countryId > 0) && (m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) + if ( (m_countryId > 0) && ( (unsigned int)m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) { return GeoIP_country_code[m_countryId]; } @@ -90,14 +90,14 @@ const char * GeoInfo::getGeoEnv( const char * pEnvName ) } else if ( strcasecmp( pEnvName, "NAME" ) == 0 ) { - if ( (m_countryId > 0) && (m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) + if ( (m_countryId > 0) && ( (unsigned int)m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) return GeoIP_country_name[m_countryId]; else if ( m_pCity ) return m_pCity->country_name; } else if ( strcasecmp( pEnvName, "CONTINENT" ) == 0 ) { - if ( (m_countryId > 0) && (m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) + if ( (m_countryId > 0) && ( (unsigned int)m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) { return GeoIP_country_continent[ m_countryId ]; } @@ -120,7 +120,7 @@ const char * GeoInfo::getGeoEnv( const char * pEnvName ) } else if ( strcasecmp( pEnvName, "CONTINENT_CODE" ) == 0 ) { - if ( (m_countryId > 0) && (m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) + if ( ( m_countryId > 0) && ( (unsigned int)m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) { return GeoIP_country_continent[m_countryId]; } @@ -175,7 +175,7 @@ int GeoInfo::addGeoEnv( IEnv * pEnv ) int count = 0; const char * pStr; int len; - if ( (m_countryId > 0) && (m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) + if ( (m_countryId > 0) && ( (unsigned int)m_countryId < sizeof( GeoIP_country_name ) / sizeof( const char *) )) { pStr = GeoIP_country_name[m_countryId]; pEnv->add( "GEOIP_COUNTRY_CODE", 18, GeoIP_country_code[m_countryId], 2 ); diff --git a/src/http/l4handler.cpp b/src/http/l4handler.cpp new file mode 100644 index 000000000..4fd458127 --- /dev/null +++ b/src/http/l4handler.cpp @@ -0,0 +1,149 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#include "l4handler.h" +#include +#include + +L4Handler::L4Handler() +{ + m_pL4conn = new L4conn(this); + m_buf = new LoopBuf(MAX_OUTGOING_BUF_ZISE); + m_iState = 0; +} + +void L4Handler::recycle() +{ + delete m_buf; + delete m_pL4conn; + delete this; +} + +int L4Handler::onReadEx() +{ + bool empty = m_pL4conn->getBuf()->empty(); + int space; + + while ( (space = m_pL4conn->getBuf()->contiguous()) > 0) + { + int n = getStream()->read(m_pL4conn->getBuf()->end(), space); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D ((getLogger(), "[%s] L4Handler: read [%d]", getLogId(), n )); + } + + if (n > 0) + m_pL4conn->getBuf()->used(n); + else if ( n == 0 ) + break; + else // if (n < 0) + { + closeBothConnection(); + return -1; + } + } + + if ( !m_pL4conn->getBuf()->empty() ) + { + m_pL4conn->doWrite(); + if ( !m_pL4conn->getBuf()->empty() && empty) + m_pL4conn->continueWrite(); + + if (m_pL4conn->getBuf()->available() <= 0 ) + { + suspendRead(); + if ( D_ENABLED( DL_LESS ) ) + LOG_D ((getLogger(), "[%s] L4Handler: suspendRead", getLogId() )); + } + } + + return 0; +} + +int L4Handler::onWriteEx() +{ + bool full = ((getBuf()->available() == 0) ? true : false); + int length; + + while ((length = getBuf()->blockSize()) > 0 ) + { + int n = getStream()->write(getBuf()->begin(), length); + if ( D_ENABLED( DL_LESS ) ) + LOG_D ((getLogger(), "[%s] L4Handler: write [%d of %d]", getLogId(), n, length )); + + if (n > 0) + getBuf()->pop_front(n); + else if ( n == 0 ) + break; + else // if (n < 0) + { + closeBothConnection(); + return -1; + } + } + + if (getBuf()->available() != 0) + { + if (full) + m_pL4conn->continueRead(); + + if ( getBuf()->empty() ) + { + suspendWrite(); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] [L4conn] m_pL4conn->continueRead", + getLogId() )); + } + } + } + + return 0; +} + +int L4Handler::init(HttpReq &req, const GSockAddr *pGSockAddr) +{ + int ret = m_pL4conn->init(pGSockAddr); + if (ret != 0) + return ret; + + m_pL4conn->getBuf()->append(req.getOrgReqLine(), req.getHttpHeaderLen()); + continueRead(); + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D ((getLogger(), "[%s] L4Handler: init web socket, reqheader [%s], len [%d]", + getLogId(), req.getOrgReqLine(), req.getHttpHeaderLen() )); + } + return 0; +} + +void L4Handler::doWrite() +{ + onWriteEx(); +} + +void L4Handler::closeBothConnection() +{ + if (m_iState != -1) + { + m_pL4conn->close(); + getStream()->close(); + m_iState = -1; + } +} + diff --git a/src/http/l4handler.h b/src/http/l4handler.h new file mode 100644 index 000000000..52fb0905d --- /dev/null +++ b/src/http/l4handler.h @@ -0,0 +1,65 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#ifndef L4TUNNEL_H +#define L4TUNNEL_H + +#include +#include +#include +#include +#include "socket/gsockaddr.h" + +class L4Handler : public HioStreamHandler +{ + +public: + L4Handler(); + ~L4Handler() {}; + + int init(HttpReq &req, const GSockAddr *pGSockAddr); + + LoopBuf* getBuf() { return m_buf; } + void continueRead() { getStream()->continueRead(); } + void suspendRead() { getStream()->suspendRead(); } + void suspendWrite() { getStream()->suspendWrite(); } + void continueWrite() { getStream()->continueWrite(); } + + void doWrite(); + void closeBothConnection(); + +private: + L4conn * m_pL4conn; + LoopBuf * m_buf; + int m_iState; + + + void recycle(); + int onTimerEx() { return 0; } + int onCloseEx() { return 0; } + int onWriteEx(); + int onReadEx(); + int onInitConnected() { return 0; }; + +public: + LOG4CXX_NS::Logger* getLogger() const { return getStream()->getLogger(); } + const char * getLogId() { return getStream()->getLogId(); } + +}; + +#endif // L4TUNNEL_H diff --git a/src/http/moov.cpp b/src/http/moov.cpp index edfb72e7b..80ac1e7b5 100644 --- a/src/http/moov.cpp +++ b/src/http/moov.cpp @@ -1377,7 +1377,7 @@ static int calc_new_moov_diff(moov_t * moov_box, float start_time, float end_tim mdat_end_offset = 0; max_duration = 0; - for(i=0;i < moov_box->track_num;i++) + for(i=0;i < (unsigned int)moov_box->track_num;i++) { //time to sampleStart, sampleEnd, chunkStart, chunkEnd t1 = moov_box->trak[i].mdia.mdhd.TimeScale * start_time; @@ -1425,7 +1425,7 @@ static int calc_new_moov_diff(moov_t * moov_box, float start_time, float end_tim moov_box->header.ExtendedSize -= 4+8*3; mdat_start_offset = moov_box->trak[0].mdia.minf.stbl.stco_co64.firstChunkOffset; - for(i=1;itrack_num;i++) + for(i=1; i < (unsigned int)moov_box->track_num; i++) { t = moov_box->trak[i].mdia.minf.stbl.stco_co64.firstChunkOffset; if(t < mdat_start_offset) @@ -1958,7 +1958,7 @@ static int moov_write_chunk(moov_data_t * moov_data, moov_t * moov_box) acc_pre=0; acc = moov_box->header.length + moov_box->mvhd.header.ExtendedSize; - for(i=0;i < moov_box->track_num; i++) + for(i=0;i < (unsigned int)moov_box->track_num; i++) { trak = & moov_box->trak[i]; stbl = & trak->mdia.minf.stbl; diff --git a/src/http/httpiolink.cpp b/src/http/ntwkiolink.cpp similarity index 72% rename from src/http/httpiolink.cpp rename to src/http/ntwkiolink.cpp index 3069cec21..f2ccacdff 100644 --- a/src/http/httpiolink.cpp +++ b/src/http/ntwkiolink.cpp @@ -15,65 +15,111 @@ * You should have received a copy of the GNU General Public License * * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ -#include "httpiolink.h" +#include "ntwkiolink.h" #include #include #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include -#include -#include -#include -#include +#include + +#include #include #include #include #include #include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "util/ssnprintf.h" #define IO_THROTTLE_READ 8 #define IO_THROTTLE_WRITE 16 #define IO_COUNTED 32 +//#define SPDY_PLAIN_DEV -HttpIOLink::HttpIOLink() +NtwkIOLink::NtwkIOLink() { } -HttpIOLink::~HttpIOLink() +NtwkIOLink::~NtwkIOLink() { } -int HttpIOLink::write( const char * pBuf, int size ) +int NtwkIOLink::write( const char * pBuf, int size ) { IOVec iov( pBuf, size ); return writev( iov, size ); } -void HttpIOLink::enableThrottle( int enable ) +void NtwkIOLink::enableThrottle( int enable ) { if ( enable ) - s_pCur_fn_list_list = &HttpIOLink::s_fn_list_list_throttle; + s_pCur_fn_list_list = &NtwkIOLink::s_fn_list_list_throttle; else - s_pCur_fn_list_list = &HttpIOLink::s_fn_list_list_normal; + s_pCur_fn_list_list = &NtwkIOLink::s_fn_list_list_normal; } +int NtwkIOLink::setupHandler( HiosProtocol verSpdy ) +{ + HioStreamHandler * pHandler; +#ifdef SPDY_PLAIN_DEV + if ( !isSSL() && (verSpdy == HIOS_PROTO_HTTP) ) + verSpdy = HIOS_PROTO_SPDY2; +#endif + setProtocol( verSpdy ); + if ( verSpdy != HIOS_PROTO_HTTP ) + { + SpdyConnection * pConn = new SpdyConnection(); + if ( !pConn ) + return -1; + setLogIdBuild( 0 ); + pConn->init( verSpdy ); + pHandler = pConn; + } + else + { + HttpConnection * pConn = HttpConnPool::getConnection(); + if ( !pConn ) + return -1; + pConn->setNtwkIOLink( this ); + pHandler = pConn; + } -int HttpIOLink::setLink( int fd, ClientInfo * pInfo, SSLContext * pSSLContext ) + pHandler->assignStream( this ); + pHandler->onInitConnected(); + return 0; + +} + +int NtwkIOLink::setLink( int fd, ClientInfo * pInfo, SSLContext * pSSLContext ) { + HioStream::reset(); setfd( fd ); m_pClientInfo = pInfo; setActiveTime( DateTime::s_curTime ); - m_iWant = HIO_WANT_READ; + setState( HIOS_CONNECTED ); + setHandler( NULL ); memset( &m_iInProcess, 0, (char *)(&m_ssl + 1) - (char *)(&m_iInProcess) ); + ++HttpGlobals::s_iIdleConns; + m_tmToken = HttpGlobals::s_tmToken; + if ( HttpGlobals::getMultiplexer()->add( this, POLLIN|POLLHUP|POLLERR ) == -1 ) + return -1; //set ssl context if ( pSSLContext ) { @@ -94,32 +140,17 @@ int HttpIOLink::setLink( int fd, ClientInfo * pInfo, SSLContext * pSSLContext ) else { setNoSSL(); + setupHandler( HIOS_PROTO_HTTP ); + } pInfo->incConn(); - if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] concurrent conn: %d", - getLogId(), pInfo->getConns() )); - onInitConnected(); - ++HttpGlobals::s_iIdleConns; - m_tmToken = HttpGlobals::s_tmToken; - return HttpGlobals::getMultiplexer()->add( this, POLLIN|POLLHUP|POLLERR ); -} - -int HttpIOLink::getServerAddrStr( char * pBuf, int len ) -{ - char achAddr[128]; - socklen_t addrlen = 128; - if ( getsockname( getfd(), (struct sockaddr *) achAddr, &addrlen ) == -1 ) - { - return 0; - } - if ( GSockAddr::ntop( (struct sockaddr *)achAddr, pBuf, len ) == NULL ) - return 0; - return strlen( pBuf ); + if ( D_ENABLED( DL_LESS )) + LOG_D(( getLogger(), "[%s] concurrent conn: %d", + getLogId(), pInfo->getConns() )); + return 0; } - -void HttpIOLink::ignoreReadBuf() +void NtwkIOLink::drainReadBuf() { //clear the inbound data buffer char achDiscard[4096]; @@ -132,7 +163,7 @@ void HttpIOLink::ignoreReadBuf() closeSocket(); } -void HttpIOLink::tryRead() +void NtwkIOLink::tryRead() { char ch; if ( ::recv( getfd(), &ch, 1, MSG_PEEK ) == 1 ) @@ -141,13 +172,13 @@ void HttpIOLink::tryRead() } } -int HttpIOLink::handleEvents( short evt ) +int NtwkIOLink::handleEvents( short evt ) { register int event = evt; if ( D_ENABLED( DL_MEDIUM )) - LOG_D(( getLogger(), "[%s] HttpIOLink::handleEvents() events=%d!", + LOG_D(( getLogger(), "[%s] NtwkIOLink::handleEvents() events=%d!", getLogId(), event )); - if ( m_iState == HC_SHUTDOWN ) + if ( getState() == HIOS_SHUTDOWN ) { if ( event & (POLLHUP|POLLERR) ) { @@ -158,10 +189,10 @@ int HttpIOLink::handleEvents( short evt ) //resetRevent( POLLIN | POLLOUT ); if ( event & POLLIN ) { - if ( !(m_iPeerShutdown & IO_HTTP_ERR) ) - ignoreReadBuf(); - else + if ( getFlag( HIO_FLAG_ABORT | HIO_FLAG_PEER_SHUTDOWN ) ) HttpGlobals::getMultiplexer()->suspendRead( this ); + else + drainReadBuf(); } } return 0; @@ -173,11 +204,9 @@ int HttpIOLink::handleEvents( short evt ) } if ( event & (POLLHUP | POLLERR )) { - m_iPeerShutdown |= IO_PEER_HUP; + setFlag( HIO_FLAG_PEER_SHUTDOWN, 1 ); m_iInProcess = 0; - if ( m_iState == HC_WAITING ) - --HttpGlobals::s_iIdleConns; - closeConnection(); + doClose(); return 0; } if ( event & POLLOUT ) @@ -185,27 +214,41 @@ int HttpIOLink::handleEvents( short evt ) (*m_pFnList->m_onWrite_fn)( this ); } m_iInProcess = 0; - if ( m_iState >= HC_CLOSING ) + if ( getState() >= HIOS_CLOSING ) { - closeConnection(); + doClose(); } return 0; } +void NtwkIOLink::doClose() +{ + if ( getHandler() ) + { + if ( isReadyToRelease() ) + { + getHandler()->recycle(); + setHandler( NULL ); + } + else + getHandler()->onCloseEx(); + } + close(); +} -void HttpIOLink::suspendRead() +void NtwkIOLink::suspendRead() { if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] HttpIOLink::suspendRead()...", getLogId() )); + LOG_D(( getLogger(), "[%s] NtwkIOLink::suspendRead()...", getLogId() )); if ( !(( isSSL() )&&( m_ssl.wantRead())) ) HttpGlobals::getMultiplexer()->suspendRead( this ); } -void HttpIOLink::continueRead() +void NtwkIOLink::continueRead() { if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] HttpIOLink::continueRead()...", getLogId() )); - m_iWant |= HIO_WANT_READ; + LOG_D(( getLogger(), "[%s] NtwkIOLink::continueRead()...", getLogId() )); + setFlag( HIO_FLAG_WANT_READ, 1 ); if (( allowRead())) { if ( D_ENABLED( DL_LESS )) @@ -214,20 +257,22 @@ void HttpIOLink::continueRead() } } -void HttpIOLink::suspendWrite() +void NtwkIOLink::suspendWrite() { if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] HttpIOLink::suspendWrite()...", getLogId() )); - m_iWant &= ~HIO_WANT_WRITE; + LOG_D(( getLogger(), "[%s] NtwkIOLink::suspendWrite()...", getLogId() )); + setFlag( HIO_FLAG_WANT_WRITE, 0 ); if ( !(( isSSL() )&&( m_ssl.wantWrite())) ) HttpGlobals::getMultiplexer()->suspendWrite(this); } -void HttpIOLink::continueWrite() +void NtwkIOLink::continueWrite() { if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] HttpIOLink::continueWrite()...", getLogId() )); - m_iWant |= HIO_WANT_WRITE; + LOG_D(( getLogger(), "[%s] NtwkIOLink::continueWrite()...", getLogId() )); + if( getFlag( HIO_FLAG_WANT_WRITE ) ) + return; + setFlag( HIO_FLAG_WANT_WRITE, 1 ); if ( allowWrite() ) { if ( D_ENABLED( DL_LESS )) @@ -240,9 +285,10 @@ void HttpIOLink::continueWrite() } } -void HttpIOLink::switchWriteToRead() +void NtwkIOLink::switchWriteToRead() { - m_iWant = HIO_WANT_READ; + setFlag( HIO_FLAG_WANT_READ, 1 ); + setFlag( HIO_FLAG_WANT_WRITE, 0 ); HttpGlobals::getMultiplexer()->switchWriteToRead( this ); } @@ -251,36 +297,43 @@ void HttpIOLink::switchWriteToRead() // SSL /////////////////////////////////////////////////////////////////////// -void HttpIOLink::updateSSLEvent() +void NtwkIOLink::updateSSLEvent() { - if ( wantWrite() ) + if ( isWantWrite() ) + { + dumpState( "updateSSLEvent", "CW" ); HttpGlobals::getMultiplexer()->continueWrite( this ); - if ( wantRead() ) + } + if ( isWantRead() ) + { + dumpState( "updateSSLEvent", "CR" ); HttpGlobals::getMultiplexer()->continueRead( this ); + } } -void HttpIOLink::checkSSLReadRet( int ret ) +void NtwkIOLink::checkSSLReadRet( int ret ) { if ( ret > 0 ) { - m_lBytesRead += ret; + bytesRecv( ret ); HttpGlobals::s_lSSLBytesRead += ret; setActiveTime( DateTime::s_curTime ); - updateSSLEvent(); + //updateSSLEvent(); } else if ( !ret ) { - if ( m_ssl.wantRead() ) - HttpGlobals::getMultiplexer()->switchWriteToRead( this ); if ( m_ssl.wantWrite() ) - HttpGlobals::getMultiplexer()->switchReadToWrite( this ); + { + dumpState( "checkSSLReadRet", "CW" ); + HttpGlobals::getMultiplexer()->continueWrite( this ); + } } - else if ( m_iState != HC_SHUTDOWN ) - m_iState = HC_CLOSING; + else if ( getState() != HIOS_SHUTDOWN ) + setState( HIOS_CLOSING ); } -int HttpIOLink::readExSSL( HttpIOLink* pThis, char * pBuf, int size ) +int NtwkIOLink::readExSSL( NtwkIOLink* pThis, char * pBuf, int size ) { int ret; assert( pBuf ); @@ -292,7 +345,7 @@ int HttpIOLink::readExSSL( HttpIOLink* pThis, char * pBuf, int size ) return ret; } -int HttpIOLink::writevExSSL( HttpIOLink * pThis, IOVec &vector, int total ) +int NtwkIOLink::writevExSSL( NtwkIOLink * pThis, IOVec &vector, int total ) { int ret = 0; @@ -336,7 +389,7 @@ int HttpIOLink::writevExSSL( HttpIOLink * pThis, IOVec &vector, int total ) written = pThis->m_ssl.write( pBuf, bufSize ); if ( written > 0 ) { - pThis->m_lBytesSent += written; + pThis->bytesSent( written ); HttpGlobals::s_lSSLBytesWritten += written; pThis->setActiveTime( DateTime::s_curTime ); ret += written; @@ -348,64 +401,93 @@ int HttpIOLink::writevExSSL( HttpIOLink * pThis, IOVec &vector, int total ) } else if ( !written ) { - pThis->setSSLAgain(); + if ( pThis->m_ssl.wantRead() ) + HttpGlobals::getMultiplexer()->continueRead( pThis ); + //pThis->setSSLAgain(); break; } - else if ( pThis->m_iState != HC_SHUTDOWN ) + else if ( pThis->getState() != HIOS_SHUTDOWN ) { - pThis->m_iState = HC_CLOSING; + pThis->setState( HIOS_CLOSING ); return -1; } } return ret; } -void HttpIOLink::setSSLAgain() +void NtwkIOLink::setSSLAgain() { - if ( m_ssl.wantRead() ) - HttpGlobals::getMultiplexer()->switchWriteToRead( this ); - if ( m_ssl.wantWrite() ) - HttpGlobals::getMultiplexer()->switchReadToWrite( this ); + if ( m_ssl.wantRead() || getFlag( HIO_FLAG_WANT_READ ) ) + { + dumpState( "setSSLAgain", "CR" ); + HttpGlobals::getMultiplexer()->continueRead( this ); + } + else + { + dumpState( "setSSLAgain", "SR" ); + HttpGlobals::getMultiplexer()->suspendRead( this ); + } + + if ( m_ssl.wantWrite() || getFlag( HIO_FLAG_WANT_WRITE ) ) + { + dumpState( "setSSLAgain", "CW" ); + HttpGlobals::getMultiplexer()->continueWrite( this ); + } + else + { + dumpState( "setSSLAgain", "SW" ); + HttpGlobals::getMultiplexer()->suspendWrite( this ); + } } -int HttpIOLink::flushSSL() +int NtwkIOLink::flush() { if ( D_ENABLED( DL_LESS )) - LOG_D(( getLogger(), "[%s] HttpIOLink::flushSSL()...", getLogId() )); + LOG_D(( getLogger(), "[%s] NtwkIOLink::flush...", getLogId() )); + if ( !isSSL() ) + return 0; int ret; switch( ( ret = getSSL()->flush() )) { case 0: - setSSLAgain(); - continueWrite(); + if ( m_ssl.wantRead() ) + { + dumpState( "flush", "CR" ); + HttpGlobals::getMultiplexer()->continueRead( this ); + } + else + { + dumpState( "flush", "CW" ); + HttpGlobals::getMultiplexer()->continueRead( this ); + } return 1; case 1: return 0; case -1: - m_iState = HC_CLOSING; + setState( HIOS_CLOSING ); break; } return ret; } -int HttpIOLink::onWriteSSL( HttpIOLink * pThis ) +int NtwkIOLink::onWriteSSL( NtwkIOLink * pThis ) { - if ( !pThis->m_ssl.wantWrite() ) + pThis->dumpState( "onWriteSSL", "none" ); + if ( pThis->m_ssl.wantWrite() ) { - int last = pThis->m_ssl.lastRead(); - if ( !pThis->m_ssl.isConnected()||( last )) + if ( !pThis->m_ssl.isConnected()||( pThis->m_ssl.lastRead() )) { pThis->SSLAgain(); -// if (( !pThis->m_ssl.isConnected() )||(last )) - return 0; + return 0; } } return pThis->doWrite(); } -int HttpIOLink::onReadSSL( HttpIOLink * pThis ) +int NtwkIOLink::onReadSSL( NtwkIOLink * pThis ) { + pThis->dumpState( "onReadSSL", "none" ); if ( pThis->m_ssl.wantRead() ) { int last = pThis->m_ssl.lastWrite(); @@ -420,7 +502,7 @@ int HttpIOLink::onReadSSL( HttpIOLink * pThis ) } -int HttpIOLink::closeSSL( HttpIOLink * pThis ) +int NtwkIOLink::closeSSL( NtwkIOLink * pThis ) { if ( D_ENABLED( DL_LESS )) LOG_D(( pThis->getLogger(), "[%s] Shutting down SSL ...", pThis->getLogId() )); @@ -437,11 +519,11 @@ int HttpIOLink::closeSSL( HttpIOLink * pThis ) /////////////////////////////////////////////////////////////////////// -int HttpIOLink::close_( HttpIOLink * pThis ) +int NtwkIOLink::close_( NtwkIOLink * pThis ) { - pThis->m_iState = HC_SHUTDOWN; + pThis->setState( HIOS_SHUTDOWN ); - if ( pThis->m_iPeerShutdown & (IO_PEER_ERR | IO_PEER_HUP) ) + if ( pThis->getFlag( HIO_FLAG_PEER_SHUTDOWN | HIO_FLAG_ABORT ) ) pThis->closeSocket(); else { @@ -464,7 +546,7 @@ int HttpIOLink::close_( HttpIOLink * pThis ) return -1; } -void HttpIOLink::closeSocket() +void NtwkIOLink::closeSocket() { if ( getfd() == -1 ) return; @@ -489,15 +571,25 @@ void HttpIOLink::closeSocket() //printf( "socket: %d closed\n", getfd() ); ::close( getfd() ); setfd( -1 ); - recycle(); + if ( getHandler() ) + { + getHandler()->recycle(); + setHandler( NULL ); + } + //recycle itself. + if ( D_ENABLED( DL_LESS )) + LOG_D(( getLogger(), "[%s] Recycle NtwkIoLink", getLogId() )); + NtwkIoLinkPool::recycle( this ); } -int HttpIOLink::onRead( HttpIOLink * pThis ) +int NtwkIOLink::onRead( NtwkIOLink * pThis ) { - return pThis->onReadEx(); + if ( pThis->getHandler() ) + return pThis->getHandler()->onReadEx(); + return -1; } -int HttpIOLink::onWrite(HttpIOLink *pThis ) +int NtwkIOLink::onWrite(NtwkIOLink *pThis ) { return pThis->doWrite(); } @@ -510,21 +602,18 @@ static int matchToken( int token ) } -void HttpIOLink::onTimer_( HttpIOLink * pThis ) +void NtwkIOLink::onTimer_( NtwkIOLink * pThis ) { if ( matchToken( pThis->m_tmToken ) ) { if ( pThis->detectClose() ) return; - if ( pThis->getState() == HC_THROTTLING ) - { - pThis->onWriteEx(); - } - pThis->onTimerEx(); + if (pThis->getHandler()) + pThis->getHandler()->onTimerEx(); } } -int HttpIOLink::checkReadRet( int ret, int size ) +int NtwkIOLink::checkReadRet( int ret, int size ) { //Note: read return 0 means TCP receive FIN, the other side shutdown the write // side of the socket, should leave it alone. Should get other signals @@ -536,20 +625,20 @@ int HttpIOLink::checkReadRet( int ret, int size ) resetRevent( POLLIN ); if ( ret > 0 ) { - m_lBytesRead += ret; + bytesRecv( ret ); HttpGlobals::s_lBytesRead += ret; setActiveTime( DateTime::s_curTime ); } else if ( ret == 0 ) { - if ( m_iState != HC_SHUTDOWN ) + if ( getState() != HIOS_SHUTDOWN ) { if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] End of stream detected, CLOSING!", getLogId() )); //have the connection closed quickly - m_iPeerShutdown |= IO_PEER_HUP; - m_iState = HC_CLOSING; + setFlag( HIO_FLAG_PEER_SHUTDOWN, 1 ); + setState( HIOS_CLOSING ); } ret = -1; } @@ -569,8 +658,8 @@ int HttpIOLink::checkReadRet( int ret, int size ) ret = 0; break; default: - if ( m_iState != HC_SHUTDOWN ) - m_iState = HC_CLOSING; + if ( getState() != HIOS_SHUTDOWN ) + setState( HIOS_CLOSING ); if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] read error: %s\n", getLogId(), strerror( errno ) )); @@ -582,7 +671,7 @@ int HttpIOLink::checkReadRet( int ret, int size ) } -int HttpIOLink::readEx( HttpIOLink* pThis, char * pBuf, int size ) +int NtwkIOLink::readEx( NtwkIOLink* pThis, char * pBuf, int size ) { int ret; assert( pBuf ); @@ -600,7 +689,7 @@ int HttpIOLink::readEx( HttpIOLink* pThis, char * pBuf, int size ) #if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) #include -int HttpIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off, size_t size ) +int NtwkIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off, size_t size ) { struct sf_hdtr hdtr; struct sf_hdtr * pHeader; @@ -631,7 +720,7 @@ int HttpIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off #if defined(sun) || defined(__sun) -int HttpIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off, size_t size ) +int NtwkIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off, size_t size ) { int n = 0 ; @@ -675,7 +764,7 @@ int HttpIOLink::sendfileEx( IOVec &vector, int headerTotal, int fdSrc, off_t off defined(__gnu_linux__)||defined(HPUX) ||\ defined(sun) || defined(__sun) -int HttpIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, size_t size ) +int NtwkIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, size_t size ) { int len = 0; int written; @@ -751,7 +840,7 @@ int HttpIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, si #else -int HttpIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, size_t size ) +int NtwkIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, size_t size ) { int len = 0; ThrottleControl * pCtrl = getThrottleCtrl(); @@ -816,7 +905,7 @@ int HttpIOLink::sendfile( IOVec &iov, int &headerTotal, int fdSrc, off_t off, si #endif -int HttpIOLink::writevEx( HttpIOLink * pThis, IOVec &vector, int total ) +int NtwkIOLink::writevEx( NtwkIOLink * pThis, IOVec &vector, int total ) { int len = ::writev( pThis->getfd(), vector.get(), vector.len() ); len = pThis->checkWriteRet( len, total ); @@ -840,7 +929,14 @@ int HttpIOLink::writevEx( HttpIOLink * pThis, IOVec &vector, int total ) } -int HttpIOLink::checkWriteRet( int len, int size ) +int NtwkIOLink::sendHeaders( IOVec &vector, int headerCount ) +{ + assert( "Should not be called." == NULL ); + return -1; +} + + +int NtwkIOLink::checkWriteRet( int len, int size ) { if ( len < size ) resetRevent( POLLOUT ); @@ -848,7 +944,7 @@ int HttpIOLink::checkWriteRet( int len, int size ) setRevent( POLLOUT ); if ( len > 0 ) { - m_lBytesSent += len; + bytesSent( len ); HttpGlobals::s_lBytesWritten += len; setActiveTime( DateTime::s_curTime ); } @@ -864,10 +960,10 @@ int HttpIOLink::checkWriteRet( int len, int size ) len = 0; break; default: - if ( m_iState != HC_SHUTDOWN ) + if ( getState() != HIOS_SHUTDOWN ) { - m_iState = HC_CLOSING; - setPeerShutdown( IO_PEER_ERR ); + setState( HIOS_CLOSING ); + setFlag( HIO_FLAG_ABORT, 1 ); } if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] write error: %s\n", @@ -879,20 +975,25 @@ int HttpIOLink::checkWriteRet( int len, int size ) return len; } -int HttpIOLink::detectClose() +int NtwkIOLink::detectClose() { - if (( getState() >= HC_THROTTLING )&& - ( getState() != HC_WRITING )) + if ( getState() == HIOS_SHUTDOWN ) + { + if ( D_ENABLED( DL_MEDIUM ) ) + LOG_D((getLogger(), "[%s] Shutdown time out!", getLogId() )); + closeSocket(); + } + else if ( getState() == HIOS_CONNECTED ) { char ch; - if ( !::recv( getfd(), &ch, 1, MSG_PEEK ) ) + if ( ( getClientInfo()->getAccess() == AC_BLOCK ) || + (::recv( getfd(), &ch, 1, MSG_PEEK ) == 0 ) ) { if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] peer connection close detected!\n", getLogId() )); //have the connection closed faster - setPeerShutdown( IO_PEER_ERR ); - - closeConnection( 1 ); + setFlag( HIO_FLAG_PEER_SHUTDOWN, 1 ); + doClose(); return 1; } } @@ -903,12 +1004,12 @@ int HttpIOLink::detectClose() // Throttle /////////////////////////////////////////////////////////////////////// -int HttpIOLink::onReadT( HttpIOLink * pThis ) +int NtwkIOLink::onReadT( NtwkIOLink * pThis ) { return pThis->doReadT(); } -int HttpIOLink::onWriteT( HttpIOLink *pThis ) +int NtwkIOLink::onWriteT( NtwkIOLink *pThis ) { if ( pThis->allowWrite() ) return pThis->doWrite(); @@ -917,7 +1018,22 @@ int HttpIOLink::onWriteT( HttpIOLink *pThis ) return 0; } -void HttpIOLink::onTimer_T( HttpIOLink * pThis ) +void NtwkIOLink::dumpState(const char * pFuncName, const char * action) +{ + if ( D_ENABLED( DL_MORE )) + LOG_D(( getLogger(), "[%s] %s(), %s, wantRead: %d, wantWrite: %d," + " allowWrite: %d, allowRead: %d," + " m_ssl.wantRead: %d, m_ssl.wantWrite: %d, " + " m_ssl.lastRead: %d, m_ssl.lastWrite: %d", + getLogId(), pFuncName, action, isWantRead(), isWantWrite(), + allowWrite(), allowRead(), + m_ssl.wantRead(), m_ssl.wantWrite(), + m_ssl.lastRead(), m_ssl.lastWrite() + )); + +} + +void NtwkIOLink::onTimer_T( NtwkIOLink * pThis ) { if ( matchToken( pThis->m_tmToken ) ) { @@ -926,39 +1042,39 @@ void HttpIOLink::onTimer_T( HttpIOLink * pThis ) // pThis->getLogId(), pThis->m_tmToken, HttpGlobals::s_tmToken )); if ( pThis->detectClose() ) return; - if ( pThis->getState() == HC_THROTTLING ) - { - pThis->onWriteEx(); - } // if ( D_ENABLED( DL_MORE )) // LOG_D(( pThis->getLogger(), "[%s] output avail:%d. state: %d \n", // pThis->getLogId(), // pThis->getClientInfo()->getThrottleCtrl().getOSQuota(), // pThis->getState() )); - if ( pThis->allowWrite() && pThis->wantWrite() ) + if ( pThis->allowWrite() && pThis->isWantWrite() ) { //pThis->doWrite(); //if ( pThis->allowWrite() && pThis->wantWrite() ) + pThis->dumpState( "onTimer_T", "CW" ); HttpGlobals::getMultiplexer()->continueWrite( pThis ); } - if ( pThis->allowRead() && pThis->wantRead() ) + if ( pThis->allowRead() && pThis->isWantRead() ) { - if ( pThis->m_iState != HC_WAITING ) - pThis->doReadT(); - if ( pThis->allowRead() && pThis->wantRead() ) + //if ( pThis->getState() != HCS_WAITING ) + // pThis->doReadT(); + //if ( pThis->allowRead() && pThis->wantRead() ) + pThis->dumpState( "onTimer_T", "CR" ); HttpGlobals::getMultiplexer()->continueRead( pThis ); } - pThis->onTimerEx(); + if ( pThis->getHandler() ) + pThis->getHandler()->onTimerEx(); } } -int HttpIOLink::readExT( HttpIOLink* pThis, char * pBuf, int size ) +int NtwkIOLink::readExT( NtwkIOLink* pThis, char * pBuf, int size ) { ThrottleControl * pTC = pThis->getThrottleCtrl(); int iQuota = pTC->getISQuota(); if ( iQuota <= 0 ) { + pThis->dumpState( "readExT", "SR" ); HttpGlobals::getMultiplexer()->suspendRead( pThis ); return 0; } @@ -973,6 +1089,7 @@ int HttpIOLink::readExT( HttpIOLink* pThis, char * pBuf, int size ) // ::write( 1, pBuf, ret ); if ( !pTC->getISQuota() ) { + pThis->dumpState( "readExT", "SR" ); HttpGlobals::getMultiplexer()->suspendRead( pThis ); } } @@ -981,13 +1098,14 @@ int HttpIOLink::readExT( HttpIOLink* pThis, char * pBuf, int size ) -int HttpIOLink::writevExT( HttpIOLink * pThis, IOVec &vector, int total ) +int NtwkIOLink::writevExT( NtwkIOLink * pThis, IOVec &vector, int total ) { int len = 0; ThrottleControl * pCtrl = pThis->getThrottleCtrl(); int Quota = pCtrl->getOSQuota(); if ( Quota <= 0 ) { + pThis->dumpState( "writevExT", "SW" ); HttpGlobals::getMultiplexer()->suspendWrite( pThis ); return 0; } @@ -1006,6 +1124,7 @@ int HttpIOLink::writevExT( HttpIOLink * pThis, IOVec &vector, int total ) if (Quota - len < 10 ) { pCtrl->useOSQuota( Quota ); + pThis->dumpState( "writevExT", "SW" ); HttpGlobals::getMultiplexer()->suspendWrite( pThis ); } else @@ -1021,7 +1140,7 @@ int HttpIOLink::writevExT( HttpIOLink * pThis, IOVec &vector, int total ) /////////////////////////////////////////////////////////////////////// -//void HttpIOLink::onTimerSSL_T( HttpIOLink * pThis ) +//void NtwkIOLink::onTimerSSL_T( NtwkIOLink * pThis ) //{ // if ( pThis->detectClose() ) // return; @@ -1036,40 +1155,42 @@ int HttpIOLink::writevExT( HttpIOLink * pThis, IOVec &vector, int total ) // pThis->onTimerEx(); //} -void HttpIOLink::onTimerSSL_T( HttpIOLink * pThis ) +void NtwkIOLink::onTimerSSL_T( NtwkIOLink * pThis ) { if ( matchToken( pThis->m_tmToken ) ) { if ( pThis->detectClose() ) return; - if ( pThis->getState() == HC_THROTTLING ) - { - pThis->onWriteEx(); - } if ( pThis->allowWrite() && ( pThis->m_ssl.wantWrite() )) onWriteSSL_T( pThis ); if ( pThis->allowRead() && ( pThis->m_ssl.wantRead() )) onReadSSL_T( pThis ); - if ( pThis->allowWrite() && pThis->wantWrite() ) + if ( pThis->allowWrite() && pThis->isWantWrite() ) { pThis->doWrite(); - if ( pThis->allowWrite() && pThis->wantWrite() ) + if ( pThis->allowWrite() && pThis->isWantWrite() ) + { + pThis->dumpState( "onTimerSSL_T", "CW" ); HttpGlobals::getMultiplexer()->continueWrite( pThis ); + } } - if ( pThis->allowRead() && pThis->wantRead() ) + if ( pThis->allowRead() && pThis->isWantRead() ) { - if ( pThis->m_iState != HC_WAITING ) - pThis->doReadT(); - if ( pThis->allowRead() && pThis->wantRead() ) + //if ( pThis->getState() != HCS_WAITING ) + // pThis->doReadT(); + //if ( pThis->allowRead() && pThis->wantRead() ) + pThis->dumpState( "onTimerSSL_T", "CR" ); HttpGlobals::getMultiplexer()->continueRead( pThis ); } - pThis->onTimerEx(); + if ( pThis->getHandler() ) + pThis->getHandler()->onTimerEx(); } } -int HttpIOLink::onReadSSL_T( HttpIOLink * pThis ) +int NtwkIOLink::onReadSSL_T( NtwkIOLink * pThis ) { + //pThis->dumpState( "onReadSSL_t", "none" ); if ( pThis->m_ssl.wantRead() ) { int last = pThis->m_ssl.lastWrite(); @@ -1083,9 +1204,10 @@ int HttpIOLink::onReadSSL_T( HttpIOLink * pThis ) return pThis->doReadT(); } -int HttpIOLink::onWriteSSL_T( HttpIOLink * pThis ) +int NtwkIOLink::onWriteSSL_T( NtwkIOLink * pThis ) { - if ( !pThis->m_ssl.wantWrite() ) + //pThis->dumpState( "onWriteSSL_T", "none" ); + if ( pThis->m_ssl.wantWrite() ) { int last = pThis->m_ssl.lastRead(); if ( !pThis->m_ssl.isConnected()||( last )) @@ -1117,7 +1239,7 @@ static char s_errUseSSL[] = "Powered By LiteSpeed Web Server
\n" "http://www.litespeedtech.com\n" "\n"; -int HttpIOLink::acceptSSL() +int NtwkIOLink::acceptSSL() { int ret = m_ssl.accept(); if ( ret == 1 ) @@ -1129,7 +1251,9 @@ int HttpIOLink::acceptSSL() &&( m_pClientInfo->incSslNewConn() > (HttpGlobals::s_iConnsPerClientHardLimit << 1) )) { - LOG_WARN(( getLogger(), "[%s] [SSL] too many new SSL connections: %d, possible SSL negociation based attack, block!", getLogId(), m_pClientInfo->getSslNewConn() )); + LOG_WARN(( getLogger(), "[%s] [SSL] too many new SSL connections: %d, " + "possible SSL negociation based attack, block!", getLogId(), + m_pClientInfo->getSslNewConn() )); m_pClientInfo->setOverLimitTime( DateTime::s_curTime ); m_pClientInfo->setAccess( AC_BLOCK ); } @@ -1146,7 +1270,7 @@ int HttpIOLink::acceptSSL() return ret; } -int HttpIOLink::SSLAgain() +int NtwkIOLink::SSLAgain() { if ( D_ENABLED( DL_LESS )) LOG_D(( getLogger(), "[%s] [SSL] SSLAgain()!\n", getLogId() )); @@ -1158,9 +1282,15 @@ int HttpIOLink::SSLAgain() break; case SSLConnection::ACCEPTING: ret = acceptSSL(); - if ( ret == 0 ) + if ( ret == 1 ) { - setState( HC_READING ); + unsigned int spdyVer = m_ssl.getSpdyVersion(); + if ( spdyVer > HIOS_PROTO_SPDY3 ) + { + LOG_ERR(( getLogger(), "[%s] bad SPDY version: %d, use HTTP", getLogId(), spdyVer )); + spdyVer = HIOS_PROTO_HTTP; + } + setupHandler( (HiosProtocol)spdyVer ); } break; case SSLConnection::SHUTDOWN: @@ -1168,27 +1298,29 @@ int HttpIOLink::SSLAgain() break; case SSLConnection::CONNECTED: if ( m_ssl.lastRead() ) - return onReadEx(); + { + if ( getHandler() ) + return getHandler()->onReadEx(); + else + return -1; + } if ( m_ssl.lastWrite() ) return doWrite(); } switch( ret ) { case 0: - if ( m_ssl.wantRead() ) - HttpGlobals::getMultiplexer()->switchWriteToRead( this ); - if ( m_ssl.wantWrite() ) - HttpGlobals::getMultiplexer()->switchReadToWrite( this ); + setSSLAgain(); break; case -1: - closeConnection(); + doClose(); break; } return ret; } -int HttpIOLink::readExSSL_T( HttpIOLink* pThis, char * pBuf, int size ) +int NtwkIOLink::readExSSL_T( NtwkIOLink* pThis, char * pBuf, int size ) { ThrottleControl * pTC = pThis->getThrottleCtrl(); int iQuota = pTC->getISQuota(); @@ -1216,7 +1348,7 @@ int HttpIOLink::readExSSL_T( HttpIOLink* pThis, char * pBuf, int size ) } -int HttpIOLink::writevExSSL_T( HttpIOLink * pThis, IOVec &vector, int total ) +int NtwkIOLink::writevExSSL_T( NtwkIOLink * pThis, IOVec &vector, int total ) { ThrottleControl * pCtrl = pThis->getThrottleCtrl(); int Quota = pCtrl->getOSQuota(); @@ -1282,7 +1414,7 @@ int HttpIOLink::writevExSSL_T( HttpIOLink * pThis, IOVec &vector, int total ) pThis->getLogId(), bufSize, written )); if ( written > 0 ) { - pThis->m_lBytesSent += written; + pThis->bytesSent( written ); HttpGlobals::s_lSSLBytesWritten += written; pThis->m_iSslLastWrite = 0; pThis->setActiveTime( DateTime::s_curTime ); @@ -1299,12 +1431,12 @@ int HttpIOLink::writevExSSL_T( HttpIOLink * pThis, IOVec &vector, int total ) pThis->setSSLAgain(); break; } - else if ( pThis->m_iState != HC_SHUTDOWN ) + else if ( pThis->getState() != HIOS_SHUTDOWN ) { if ( D_ENABLED( DL_MORE )) LOG_D(( "[%s] SSL error: %s, mark connection to be closed", pThis->getLogId(), SSLError().what() )); - pThis->m_iState = HC_CLOSING; + pThis->setState( HIOS_CLOSING ); return -1; } } @@ -1322,7 +1454,7 @@ int HttpIOLink::writevExSSL_T( HttpIOLink * pThis, IOVec &vector, int total ) return ret; } -void HttpIOLink::suspendEventNotify() +void NtwkIOLink::suspendEventNotify() { if ( !HttpGlobals::s_iMultiplexerType ) { @@ -1332,7 +1464,7 @@ void HttpIOLink::suspendEventNotify() } } -void HttpIOLink::resumeEventNotify() +void NtwkIOLink::resumeEventNotify() { if ( !HttpGlobals::s_iMultiplexerType ) { @@ -1342,7 +1474,7 @@ void HttpIOLink::resumeEventNotify() } } -void HttpIOLink::changeClientInfo( ClientInfo * pInfo ) +void NtwkIOLink::changeClientInfo( ClientInfo * pInfo ) { if ( pInfo == m_pClientInfo ) return; @@ -1351,5 +1483,17 @@ void HttpIOLink::changeClientInfo( ClientInfo * pInfo ) m_pClientInfo = pInfo; } +static const char * s_pProtoString[] = { "", ":SPDY2", ":SPDY3" }; +const char * NtwkIOLink::buildLogId() +{ + AutoStr2 & id = getIdBuf(); + int len ; + char * p = id.buf(); + len = safe_snprintf( id.buf(), MAX_LOGID_LEN, "%s:%hu%s", + m_pClientInfo->getAddrString(), getRemotePort(), s_pProtoString[ (int)getProtocol() ] ); + id.setLen( len ); + p += len; + return id.c_str(); +} diff --git a/src/http/httpiolink.h b/src/http/ntwkiolink.h similarity index 65% rename from src/http/httpiolink.h rename to src/http/ntwkiolink.h index 12ebe0fba..425ed7497 100644 --- a/src/http/httpiolink.h +++ b/src/http/ntwkiolink.h @@ -21,52 +21,31 @@ #include -#include #include +#include #include #include +#include #include -#define IO_PEER_HUP 1 -#define IO_PEER_ERR 2 #define IO_HTTP_ERR 4 +class VHostMap; class SSLConnection; class SSLContext; struct sockaddr; -enum -{ - HC_WAITING, - HC_READING, - HC_READING_BODY, - HC_EXT_AUTH, - HC_THROTTLING, - HC_PROCESSING, - HC_REDIRECT, - HC_WRITING, - HC_AIO_PENDING, - HC_AIO_COMPLETE, - HC_COMPLETE, - HC_SHUTDOWN, - HC_CLOSING -}; - -#define HIO_WANT_READ 1 -#define HIO_WANT_WRITE 2 - -class HttpIOLink : public EventReactor, public OutputStream - , public LOG4CXX_NS::ILog +class NtwkIOLink : public EventReactor, public HioStream { private: - typedef int (*writev_fn)( HttpIOLink* pThis, IOVec &vector, int total ); - typedef int (*read_fn)( HttpIOLink* pThis, char *pBuf, int size ); - typedef int (*onRW_fn)( HttpIOLink * pThis ); - typedef void (*onTimer_fn)( HttpIOLink * pThis ); - typedef int (*close_fn)( HttpIOLink * pThis); + typedef int (*writev_fn)( NtwkIOLink* pThis, IOVec &vector, int total ); + typedef int (*read_fn)( NtwkIOLink* pThis, char *pBuf, int size ); + typedef int (*onRW_fn)( NtwkIOLink * pThis ); + typedef void (*onTimer_fn)( NtwkIOLink * pThis ); + typedef int (*close_fn)( NtwkIOLink * pThis); class fn_list { public: @@ -112,29 +91,25 @@ class HttpIOLink : public EventReactor, public OutputStream ClientInfo * m_pClientInfo; + const VHostMap * m_pVHostMap; long m_lActiveTime; + unsigned short m_iRemotePort; - char m_iWant; char m_iInProcess; char m_iPeerShutdown; - char m_iState; int m_tmToken; int m_iSslLastWrite; - off_t m_lBytesRead; - off_t m_lBytesSent; SSLConnection m_ssl; class fn_list * m_pFnList; - HttpIOLink( const HttpIOLink& rhs ); - void operator=( const HttpIOLink& rhs ); + NtwkIOLink( const NtwkIOLink& rhs ); + void operator=( const NtwkIOLink& rhs ); - bool wantRead() const - { return m_iWant & HIO_WANT_READ; } int doRead() { - if ( wantRead() ) - return onReadEx(); + if ( isWantRead() ) + return getHandler()->onReadEx(); else suspendRead(); return 0; @@ -142,14 +117,14 @@ class HttpIOLink : public EventReactor, public OutputStream int doReadT() { - if ( wantRead() ) + if ( isWantRead() ) { if ( allowRead() ) - return onReadEx(); + return getHandler()->onReadEx(); else { suspendRead(); - m_iWant |= HIO_WANT_READ; + setFlag( HIO_FLAG_WANT_READ, 1 ); } } else @@ -159,8 +134,14 @@ class HttpIOLink : public EventReactor, public OutputStream int doWrite() { - if ( m_iWant & HIO_WANT_WRITE ) - return onWriteEx(); + if ( isWantWrite() ) + return getHandler()->onWriteEx(); + else + { + suspendWrite(); + if ( isSSL() ) + flush(); + } return 0; } @@ -168,66 +149,76 @@ class HttpIOLink : public EventReactor, public OutputStream int checkReadRet( int ret, int size ); void setSSLAgain(); - static int writevEx ( HttpIOLink* pThis, IOVec &vector, int total ); - static int writevExT ( HttpIOLink* pThis, IOVec &vector, int total ); - static int writevExSSL ( HttpIOLink* pThis, IOVec &vector, int total ); - static int writevExSSL_T( HttpIOLink* pThis, IOVec &vector, int total ); - - static int readEx ( HttpIOLink* pThis, char * pBuf, int size ); - static int readExT ( HttpIOLink* pThis, char * pBuf, int size ); - static int readExSSL ( HttpIOLink* pThis, char * pBuf, int size ); - static int readExSSL_T ( HttpIOLink* pThis, char * pBuf, int size ); - - static int onReadSSL( HttpIOLink * pThis ); - static int onReadSSL_T( HttpIOLink * pThis ); - static int onReadT( HttpIOLink *pThis ); - static int onRead(HttpIOLink *pThis ); - - static int onWriteSSL( HttpIOLink * pThis ); - static int onWriteSSL_T( HttpIOLink * pThis ); - static int onWriteT( HttpIOLink *pThis ); - static int onWrite(HttpIOLink *pThis ); - - static int close_( HttpIOLink * pThis ); - static int closeSSL( HttpIOLink * pThis ); - static void onTimer_T( HttpIOLink * pThis ); - static void onTimer_( HttpIOLink * pThis ); - static void onTimerSSL_T( HttpIOLink * pThis ); - - void ignoreReadBuf(); + static int writevEx ( NtwkIOLink* pThis, IOVec &vector, int total ); + static int writevExT ( NtwkIOLink* pThis, IOVec &vector, int total ); + static int writevExSSL ( NtwkIOLink* pThis, IOVec &vector, int total ); + static int writevExSSL_T( NtwkIOLink* pThis, IOVec &vector, int total ); + + static int readEx ( NtwkIOLink* pThis, char * pBuf, int size ); + static int readExT ( NtwkIOLink* pThis, char * pBuf, int size ); + static int readExSSL ( NtwkIOLink* pThis, char * pBuf, int size ); + static int readExSSL_T ( NtwkIOLink* pThis, char * pBuf, int size ); + + static int onReadSSL( NtwkIOLink * pThis ); + static int onReadSSL_T( NtwkIOLink * pThis ); + static int onReadT( NtwkIOLink *pThis ); + static int onRead(NtwkIOLink *pThis ); + + static int onWriteSSL( NtwkIOLink * pThis ); + static int onWriteSSL_T( NtwkIOLink * pThis ); + static int onWriteT( NtwkIOLink *pThis ); + static int onWrite(NtwkIOLink *pThis ); + + static int close_( NtwkIOLink * pThis ); + static int closeSSL( NtwkIOLink * pThis ); + static void onTimer_T( NtwkIOLink * pThis ); + static void onTimer_( NtwkIOLink * pThis ); + static void onTimerSSL_T( NtwkIOLink * pThis ); + + void drainReadBuf(); bool allowWrite() const { return m_pClientInfo->allowWrite(); } - int detectClose(); int write( const char * pBuf, int size ); int sendfileEx( IOVec &vector, int total, int fdSrc, off_t off, size_t size ); int my_sendfileEx( int fdSrc, off_t off, size_t size ); void updateSSLEvent(); void checkSSLReadRet( int ret ); + + int setupHandler( HiosProtocol verSpdy ); + void doClose(); - virtual int onReadEx() = 0; - virtual int onWriteEx() = 0; - virtual void closeConnection( int canceled = 0 ) = 0; - virtual int onTimerEx() = 0; - virtual int onInitConnected() = 0; - virtual void recycle() = 0; + void dumpState(const char * pFuncName, const char * action); -protected: +public: + void setRemotePort( unsigned short port ) + { + m_iRemotePort = port; + setLogIdBuild( 0 ); + }; + + unsigned short getRemotePort() const { return m_iRemotePort; }; + + int sendHeaders( IOVec &vector, int headerCount ); + + const char * buildLogId(); + +public: void closeSocket(); bool allowRead() const { return m_pClientInfo->allowRead(); } - char wantWrite() const { return m_iWant & HIO_WANT_WRITE; } void setActiveTime( long lTime ) { m_lActiveTime = lTime; } int close() { return (*m_pFnList->m_close_fn)( this ); } + int detectClose(); public: - HttpIOLink(); - virtual ~HttpIOLink(); + NtwkIOLink(); + ~NtwkIOLink(); char inProcess() const { return m_iInProcess; } @@ -237,15 +228,12 @@ class HttpIOLink : public EventReactor, public OutputStream // Output stream interfaces bool canHold( int size ) { return allowWrite(); } - void setPeerShutdown( int s) { m_iPeerShutdown |= s; } - int isConnCanceled() { return m_iPeerShutdown & IO_PEER_ERR; } - int writev( IOVec &vector, int total ) { return (*m_pFnList->m_writev_fn)( this, vector, total ); } int sendfile( IOVec &vector, int &total, int fdSrc, off_t off, size_t size ); - int flush() { return 0; } + int flush(); void setNoSSL() { m_pFnList = s_pCur_fn_list_list->m_pNoSSL; } @@ -262,7 +250,6 @@ class HttpIOLink : public EventReactor, public OutputStream int SSLAgain(); int acceptSSL(); - int flushSSL(); int setLink( int fd, ClientInfo * pInfo, SSLContext * pSSLContext ); @@ -281,7 +268,7 @@ class HttpIOLink : public EventReactor, public OutputStream //Event driven IO interface int handleEvents( short event ); - void setNotWantRead() { m_iWant &= ~HIO_WANT_READ; } + void setNotWantRead() { setFlag( HIO_FLAG_WANT_READ, 0 ); } void suspendRead(); void continueRead(); void suspendWrite(); @@ -304,12 +291,8 @@ class HttpIOLink : public EventReactor, public OutputStream { return m_pClientInfo; } ThrottleControl* getThrottleCtrl() const { return &( m_pClientInfo->getThrottleCtrl() ); } - char getState() const - { return m_iState; } - void setState( char state ) - { m_iState = state; } int isClosing() const - { return m_iState >= HC_SHUTDOWN; } + { return getState() >= HIOS_SHUTDOWN; } static void enableThrottle( int enable ); int isThrottle() const { return m_pFnList->m_onTimer_fn != onTimer_; } @@ -317,14 +300,11 @@ class HttpIOLink : public EventReactor, public OutputStream void resumeEventNotify(); void tryRead(); + + void tobeClosed() { setState(HIOS_CLOSING); } - int getServerAddrStr( char * pBuf, int len ); - - off_t getBytesRead() const { return m_lBytesRead; } - void resetBytesRead() { m_lBytesRead = 0; } - - off_t getBytesSent() const { return m_lBytesSent; } - void resetBytesSent() { m_lBytesSent = 0; } + void setVHostMap( const VHostMap* pMap ){ m_pVHostMap = pMap; } + const VHostMap * getVHostMap() const { return m_pVHostMap; } }; diff --git a/src/http/ntwkiolinkpool.cpp b/src/http/ntwkiolinkpool.cpp new file mode 100644 index 000000000..b55add959 --- /dev/null +++ b/src/http/ntwkiolinkpool.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * Open LiteSpeed is an open source HTTP server. * + * Copyright (C) 2013 LiteSpeed Technologies, Inc. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see http://www.gnu.org/licenses/. * + *****************************************************************************/ + +#include "ntwkiolinkpool.h" +#include "ntwkiolink.h" + +NtwkIoLinkPool::NtwkIoLinkPool() +{ + +} + +NtwkIoLinkPool::NtwkIoLinkPool(const NtwkIoLinkPool& other) +{ + +} + +NtwkIoLinkPool::~NtwkIoLinkPool() +{ + +} + +void NtwkIoLinkPool::recycle( NtwkIOLink* pConn ) +{ s_pool.recycle( pConn ); } + +NtwkIOLink* NtwkIoLinkPool::get() +{ + return s_pool.get(); +} + +void NtwkIoLinkPool::recycle( NtwkIOLink** pConn, int n ) +{ s_pool.recycle( (void **)pConn, n ); } + +int NtwkIoLinkPool::get( NtwkIOLink** pConn, int n) +{ + return s_pool.get( pConn, n); +} diff --git a/src/http/ntwkiolinkpool.h b/src/http/ntwkiolinkpool.h new file mode 100644 index 000000000..e87a62c82 --- /dev/null +++ b/src/http/ntwkiolinkpool.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * Open LiteSpeed is an open source HTTP server. * + * Copyright (C) 2013 LiteSpeed Technologies, Inc. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see http://www.gnu.org/licenses/. * + *****************************************************************************/ + +#ifndef NTWKIOLINKPOOL_H +#define NTWKIOLINKPOOL_H + +#include + +class NtwkIOLink; + +class NtwkIoLinkPool : public ObjPool +{ + typedef ObjPool Pool; + static Pool s_pool; + + NtwkIoLinkPool(); + NtwkIoLinkPool(const NtwkIoLinkPool& other); + ~NtwkIoLinkPool(); +public: + static void recycle( NtwkIOLink* pConn ); + static NtwkIOLink* get(); + static void recycle( NtwkIOLink** pConn, int n ); + static int get( NtwkIOLink** pConn, int n ); + +public: +}; + +#endif // NTWKIOLINKPOOL_H diff --git a/src/http/requestvars.cpp b/src/http/requestvars.cpp index 775aca048..69b65f344 100644 --- a/src/http/requestvars.cpp +++ b/src/http/requestvars.cpp @@ -407,8 +407,6 @@ static int ServerVarNameLen[REF_EXT_COUNT] = 7, 10, 8, 10, 13, 12, 13, 22 }; -static const char * s_isHttps[2] = { "off", "on" }; - const char * RequestVars::getVarNameStr( int var_id, int &len ) { var_id -= REF_BEGIN; @@ -704,7 +702,7 @@ int RequestVars::getReqVar( HttpConnection * pConn, int type, char * &pValue, in i = pReq->getURILen(); return i; case REF_BYTES_IN: - i = StringTool::str_off_t( pValue, bufLen, pConn->getBytesRead() ); + i = StringTool::str_off_t( pValue, bufLen, pConn->getBytesRecv() ); return i; case REF_BYTES_OUT: i = StringTool::str_off_t( pValue, bufLen, pConn->getBytesSent() ); diff --git a/src/http/rewriteengine.cpp b/src/http/rewriteengine.cpp index 0c7c25555..05de9370a 100644 --- a/src/http/rewriteengine.cpp +++ b/src/http/rewriteengine.cpp @@ -738,8 +738,6 @@ int RewriteEngine::expandEnv( const RewriteRule * pRule, HttpConnection * pConn const char * pKeyEnd; const char * pValue; const char * pValEnd; - char achCacheCtrl[REWRITE_BUF_SIZE]; - int ccLen = 0; int len = REWRITE_BUF_SIZE; char achBuf[REWRITE_BUF_SIZE]; if ( !pEnv ) diff --git a/src/http/rewriterule.cpp b/src/http/rewriterule.cpp index 0c0fb0405..8dee5cf33 100644 --- a/src/http/rewriterule.cpp +++ b/src/http/rewriterule.cpp @@ -34,11 +34,11 @@ static const char * s_pCurLine = NULL; static const char * s_pLogId = NULL; static LOG4CXX_NS::Logger * s_pLogger = NULL; -static void parse_error( const char * pError ) -{ - LOG_ERR(( s_pLogger, "[%s] rewrite: %s while parsing: %s", - s_pLogId, pError, s_pCurLine )); -} +// static void parse_error( const char * pError ) +// { +// LOG_ERR(( s_pLogger, "[%s] rewrite: %s while parsing: %s", +// s_pLogId, pError, s_pCurLine )); +// } void RewriteRule::setLogger( LOG4CXX_NS::Logger * pLogger, const char * pId) { diff --git a/src/http/staticfilecachedata.cpp b/src/http/staticfilecachedata.cpp index 30fe103c1..3e5e2c67b 100644 --- a/src/http/staticfilecachedata.cpp +++ b/src/http/staticfilecachedata.cpp @@ -40,6 +40,7 @@ #include #include #include +#include "http/httprespheaders.h" static size_t s_iMaxInMemCacheSize = 4096; static size_t s_iMaxMMapCacheSize = 256 * 1024; @@ -676,10 +677,7 @@ int StaticFileCacheData::buildGzipPath() { unsigned char achHash[MD5_DIGEST_LENGTH]; char achPath[4096]; - MD5_CTX md5_ctx; - MD5_Init( &md5_ctx ); - MD5_Update( &md5_ctx, m_real.c_str(), m_real.len() ); - MD5_Final( achHash, &md5_ctx ); + StringTool::getMd5(m_real.c_str(), m_real.len(), achHash); struct stat st; int n = snprintf( achPath, 4096, "%s/%x/%x/", s_gzipCachePath, achHash[0]>>4, achHash[0]&0xf ); if (( nio_stat( achPath, &st ) == -1 )&&( errno == ENOENT )) @@ -769,7 +767,6 @@ int StaticFileCacheData::readyCacheData( int ret; if (( compress )&&(m_pMimeType->getExpires()->compressable() )) { - char * p = pFileName + m_real.len(); ret = readyGziped(); if ( ret == 0 ) { diff --git a/src/http/staticfilehandler.cpp b/src/http/staticfilehandler.cpp index 735f0d8f4..7142653a3 100644 --- a/src/http/staticfilehandler.cpp +++ b/src/http/staticfilehandler.cpp @@ -88,7 +88,7 @@ inline int buildStaticFileHeaders( HttpResp * pResp, StaticFileData * pData ) #include #define READ_BUF_SIZE 8192 -static int cacheSend( HttpConnection* pConn, StaticFileData * pData, off_t remain ) +static int cacheSend( HttpConnection* pConn, StaticFileData * pData, int remain ) { const char * pBuf; off_t written; @@ -130,29 +130,29 @@ static int cacheSend( HttpConnection* pConn, StaticFileData * pData, off_t remai return ( remain > 0 ); } -static int cacheSend( HttpConnection* pConn, off_t written, - const char * pPrefixBuf, int &prefixLen ) -{ - StaticFileData* pData = pConn->getReq()->getStaticFileData(); - long len = (written < READ_BUF_SIZE)? written : READ_BUF_SIZE ; - const char * pBuf; - pBuf = pData->getECache()->getCacheData( - pData->getCurPos(), written, HttpGlobals::g_achBuf, len ); - if ( written <= 0 ) - { - return -1; - } - IOVec iov; - iov.append( pPrefixBuf, prefixLen ); - iov.append( pBuf, written ); - int total = prefixLen + written; - written = pConn->writeRespBodyv( iov, total ); - if ( written - prefixLen > 0 ) - pData->incCurPos( written - prefixLen ); - else - prefixLen = written; - return ( pData->getRemain() > 0 ); -} +// static int cacheSend( HttpConnection* pConn, int written, +// const char * pPrefixBuf, int &prefixLen ) +// { +// StaticFileData* pData = pConn->getReq()->getStaticFileData(); +// long len = (written < READ_BUF_SIZE)? written : READ_BUF_SIZE ; +// const char * pBuf; +// pBuf = pData->getECache()->getCacheData( +// pData->getCurPos(), written, HttpGlobals::g_achBuf, len ); +// if ( written <= 0 ) +// { +// return -1; +// } +// IOVec iov; +// iov.append( pPrefixBuf, prefixLen ); +// iov.append( pBuf, written ); +// int total = prefixLen + written; +// written = pConn->writeRespBodyv( iov, total ); +// if ( written - prefixLen > 0 ) +// pData->incCurPos( written - prefixLen ); +// else +// prefixLen = written; +// return ( pData->getRemain() > 0 ); +// } static int addExpiresHeader( HttpResp * pResp, StaticFileCacheData * pData, const ExpiresCtrl *pExpires ) @@ -172,22 +172,15 @@ static int addExpiresHeader( HttpResp * pResp, StaticFileCacheData * pData, default: return 0; } - AutoBuf & buf = pResp->getOutputBuf(); - int avail = buf.available(); - if ( avail < 35 + 22 + RFC_1123_TIME_LEN ) - { - if ( buf.grow( 35 + 22 + RFC_1123_TIME_LEN ) == -1 ) - return SC_500; - avail = buf.available(); - } - int n = safe_snprintf( buf.end(), buf.available(), - "Cache-Control: max-age=%d\r\n" - "Expires: ", age ); - buf.used( n ); - DateTime::getRFCTime( expire, buf.end() ); - buf.used( RFC_1123_TIME_LEN ); - buf.append( '\r' ); - buf.append( '\n' ); + + char sTemp[RFC_1123_TIME_LEN + 1] = {0}; + HttpRespHeaders & buf = pResp->getHeaders(); + buf.add(HttpHeader::H_CACHE_CTRL, "Cache-Control", 13, "max-age=", 8); + int n = safe_snprintf(sTemp, RFC_1123_TIME_LEN, "%d", age); + buf.appendLastVal("Cache-Control", 13, sTemp, n); + + DateTime::getRFCTime( expire, sTemp ); + buf.add(HttpHeader::H_EXPIRES, "Expires", 7, sTemp, RFC_1123_TIME_LEN); return 0; } @@ -208,7 +201,7 @@ static int processFlvStream( HttpConnection * pConn, off_t start ) { HttpResp * pResp = pConn->getResp(); pECache->incRef(); - pResp->reset(); + pConn->resetResp(); pResp->prepareHeaders( pReq, 0 ); pResp->iovAppend( pData->getCache()->getHeaderBuf(), @@ -219,7 +212,6 @@ static int processFlvStream( HttpConnection * pConn, off_t start ) pResp->setContentLen( pData->getECache()->getFileSize() - start + FLV_HEADER_LEN ); pResp->appendContentLenHeader(); - pResp->endHeader(); pResp->finalizeHeader( pReq->getVersion(), pReq->getStatusCode()); pResp->appendExtra( FLV_HEADER, FLV_HEADER_LEN ); pResp->written( FLV_HEADER_LEN ); @@ -277,11 +269,10 @@ int calcMoovContentLen( HttpConnection * pConn, off_t &contentLen ) } } - static char mdat_header64[16] = { 0, 0, 0, 1, 'm', 'd', 'a', 't' }; + //static char mdat_header64[16] = { 0, 0, 0, 1, 'm', 'd', 'a', 't' }; uint64_t mdat_start; uint64_t mdat_size; int mdat_64bit; - uint32_t * pLen32; ret= get_mdat( pECache->getfd(), @@ -445,7 +436,7 @@ int processH264Stream( HttpConnection * pConn, double start ) moov_data->start_time = start; pECache->incRef(); - pConn->getResp()->reset(); + pConn->resetResp(); off_t contentLen = 0; if ( calcMoovContentLen( pConn, contentLen ) == -1 ) @@ -459,7 +450,7 @@ int processH264Stream( HttpConnection * pConn, double start ) pConn->setupRespCache(); //pConn->getReq()->setVersion( HTTP_1_0 ); pConn->getReq()->keepAlive( 0 ); - pConn->getResp()->getOutputBuf().append( "Content-Type: video/mp4\r\n", 25 ); + pConn->getResp()->getHeaders().add(HttpHeader::H_CONTENT_TYPE, "Content-Type", 12, "video/mp4", 9 ); pConn->prepareDynRespHeader(0, 2 ); @@ -606,7 +597,7 @@ int StaticFileHandler::process( HttpConnection * pConn, const HttpHandler * pHan pReq->smartKeepAlive( pCache->getMimeType()->getMIME()->c_str() ); if ( !isSSI ) //Xuedong Add for SSI { - pResp->reset(); + pConn->resetResp(); pResp->prepareHeaders( pReq, RANGE_HEADER_LEN ); switch( code ) { @@ -632,7 +623,6 @@ int StaticFileHandler::process( HttpConnection * pConn, const HttpHandler * pHan pResp->addGzipEncodingHeader(); } } - pResp->endHeader(); pResp->finalizeHeader( pReq->getVersion(), pReq->getStatusCode()); } //Xuedong Add for SSI Start else @@ -729,13 +719,8 @@ static int buildRangeHeaders( HttpConnection* pConn, HttpRange& range ) StaticFileData * pData1 = pConn->getReq()->getStaticFileData(); StaticFileCacheData * pData = pData1->getCache(); int bodyLen; - AutoBuf & buf = pResp->getOutputBuf(); - - if ( buf.available() < 80 ) - { - if ( buf.grow( 80 ) == -1 ) - return SC_500; - } + HttpRespHeaders & buf = pResp->getHeaders(); + if ( range.count() == 1 ) { pResp->iovAppend( pData->getHeaderBuf(), pData->getHeaderLen() ); @@ -743,10 +728,13 @@ static int buildRangeHeaders( HttpConnection* pConn, HttpRange& range ) int ret = range.getContentOffset( 0, begin, end ); if ( ret ) return SC_500; - ret = range.getContentRangeString( 0, buf.end(), 80 ); + + char sTemp[8192]; + ret = range.getContentRangeString( 0, sTemp, 8191 ); if ( ret == -1 ) return SC_500; - buf.used( ret ); + buf.add(HttpHeader::H_CONTENT_RANGE, "Content-Range", 13, sTemp, ret); + bodyLen = end - begin; pData1->setCurPos( begin ); pData1->setCurEnd( end ); @@ -755,9 +743,8 @@ static int buildRangeHeaders( HttpConnection* pConn, HttpRange& range ) { pResp->iovAppend( pData->getHeaderBuf(), pData->getValidateHeaderLen() ); range.beginMultipart(); - buf.used( - safe_snprintf( buf.end(), 80, "Content-Type: multipart/byteranges; boundary=%s\r\n", - range.getBoundary() ) ); + buf.add(HttpHeader::H_CONTENT_RANGE, "Content-Range", 13, "multipart/byteranges; boundary=", 31); + buf.appendLastVal("Content-Range", 13, range.getBoundary(), strlen(range.getBoundary()) ); bodyLen = range.getMultipartBodyLen( pData->getMimeType()->getMIME() ); } pResp->setContentLen( bodyLen ); @@ -769,7 +756,7 @@ static int buildRangeHeaders( HttpConnection* pConn, HttpRange& range ) static int sendMultipart( HttpConnection * pConn, HttpRange& range ) { - off_t iRemain; + long iRemain; int ret = 0; StaticFileData* pData = pConn->getReq()->getStaticFileData(); while( true ) @@ -850,27 +837,16 @@ static int processRange( HttpConnection * pConn, HttpReq * pReq, const char *pRa delete range; if ( ret == SC_416 ) //Range unsatisfiable { - AutoBuf &buf = pConn->getResp()->getOutputBuf(); - if ( buf.capacity() < 60 ) - { - if ( buf.grow( 60 ) ) - return SC_500; - } + HttpRespHeaders &buf = pConn->getResp()->getHeaders(); + buf.add(HttpHeader::H_CONTENT_RANGE, "Content-Range", 13, "bytes */", 8); int n; + char sTemp[32] = {0}; if ( sizeof( off_t ) == 8 ) - { - n = safe_snprintf( buf.end(), buf.size(), - "Content-Range: bytes */%lld\r\n", - (long long)pData->getCache()->getFileSize()); - } + n = safe_snprintf( sTemp, 31, "%lld", (long long)pData->getCache()->getFileSize()); else - { - n = safe_snprintf( buf.end(), buf.size(), - "Content-Range: bytes */%ld\r\n", - (long)pData->getCache()->getFileSize()); - } - buf.used( n ); + n = safe_snprintf( sTemp, 31, "%ld", (long)pData->getCache()->getFileSize()); + buf.appendLastVal("Content-Range", 13, sTemp, n); } } else @@ -883,10 +859,9 @@ static int processRange( HttpConnection * pConn, HttpReq * pReq, const char *pRa { HttpResp * pResp = pConn->getResp(); pECache->incRef(); - pResp->reset(); + pConn->resetResp(); pResp->prepareHeaders( pReq, RANGE_HEADER_LEN ); ret = buildRangeHeaders( pConn, *range); - pResp->endHeader(); pResp->finalizeHeader( pReq->getVersion(), pReq->getStatusCode()); if ( !ret ) { diff --git a/src/main/httpserver.cpp b/src/main/httpserver.cpp index 7f2983c98..05e14167a 100644 --- a/src/main/httpserver.cpp +++ b/src/main/httpserver.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -73,6 +74,9 @@ #define STATUS_FILE DEFAULT_TMP_DIR "/.status" #define FILEMODE 0644 +#include "sslpp/sslocspstapling.h" + + static int s_achPid[256]; static int s_curPid = 0; @@ -100,7 +104,8 @@ void HttpServer::cleanPid() { int pid; sigset_t newmask, oldmask; - + ExtWorker * pWorker; + sigemptyset( &newmask); sigaddset( &newmask, SIGCHLD ); if ( sigprocmask( SIG_BLOCK, &newmask, &oldmask ) < 0 ) @@ -111,7 +116,9 @@ void HttpServer::cleanPid() pid = s_achPid[--s_curPid]; if ( D_ENABLED( DL_LESS ) ) LOG_D(( "Remove pid: %d", pid )); - PidRegistry::remove( pid ); + pWorker = PidRegistry::remove( pid ); + if ( pWorker ) + pWorker->removePid( pid ); } sigprocmask( SIG_SETMASK, &oldmask, NULL ); @@ -150,6 +157,7 @@ class HttpServerImpl ExtAppRegistry::init(); HttpGlobals::setHttpMime( &m_httpMime ); m_serverContext.allocateInternal(); + HttpResp::buildCommonHeaders(); #ifdef USE_CARES Adns::init(); @@ -192,19 +200,8 @@ class HttpServerImpl const char *pKeyFile, const char * pCAFile, const char * pCAPath, const char * pCiphers, int certChain, int cv, int renegProtect ); - int setupSSLContext( VHostMap * pVHostMap, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, const char * pCAPath, - const char * pCiphers, int certChain, int cv, int renegProtect = 1 ); - - int setupSSLContext( HttpListener *pListener, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, - const char * pCAPath, - const char * pCiphers, int certChain, int cv, int renegProtect = 1); - HttpListener* addSSLListener( const char * pName, const char * pAddr, - const char * pCertFile, const char * pKeyFile, - const char * pCAFile, const char * pCAPath, - const char * pCiphers, int certChain = 0 , int cv = 0, int renegProtect = 1); + SSLContext * pSSL ); int removeListener( const char * pName ); @@ -323,7 +320,6 @@ int HttpServerImpl::start() m_pid = getpid(); DateTime::s_curTime = time( NULL ); HttpSignals::init(sigchild); - HttpResp::buildCommonHeaders(); HttpCgiTool::buildServerEnv(); if ( isServerOk() == -1 ) return -1; @@ -425,7 +421,7 @@ int HttpServerImpl::generateProcessReport( int fd ) char * p = achBuf; p += safe_snprintf( p, &achBuf[4096] - p, "VERSION: LiteSpeed Web Server/%s/%s\n", "Open", - VERSION ); + PACKAGE_VERSION ); p += safe_snprintf( p, &achBuf[4096] - p, "UPTIME:" ); if ( days ) @@ -533,68 +529,27 @@ HttpListener * HttpServerImpl::addListener( const char * pName, const char * pAd return pListener; } -int HttpServerImpl::setupSSLContext( VHostMap * pVHostMap, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, const char * pCAPath, - const char * pCiphers, int certChain, int cv, int renegProtect ) -{ - SSLContext* pContext = HttpServerImpl::newSSLContext( - pVHostMap->getSSLContext(), pCertFile, - pKeyFile, pCAFile, pCAPath, pCiphers, certChain, cv, renegProtect ); - if ( pContext ) - { - pVHostMap->setSSLContext( pContext ); - if ( pContext->initSNI( pVHostMap ) == -1 ) - { - LOG_WARN(( "[SSL] TLS extension is not available in openssl library on this server, " - "server name indication is disabled, you will not able to use use per vhost" - " SSL certificates sharing one IP. Please upgrade your OpenSSL lib if you want to use this feature." - )); - - } - return 0; - } - else - return -1; -} - -int HttpServerImpl::setupSSLContext( HttpListener *pListener, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, const char * pCAPath, - const char * pCiphers, int certChain, int cv, int renegProtect ) -{ - return setupSSLContext( pListener->getVHostMap(), pCertFile, - pKeyFile, pCAFile, pCAPath, pCiphers, certChain, cv, renegProtect ); -} +HttpListener* HttpServerImpl::addSSLListener( const char * pName, const char * pAddr, SSLContext * pSSL ) -HttpListener* HttpServerImpl::addSSLListener( const char * pName, const char * pAddr, - const char * pCertFile, const char * pKeyFile, - const char * pCAFile, const char * pCAPath, - const char * pCiphers, - int certChain , int cv, int renegProtect ) { HttpListener* pListener = NULL; - if (!(( pName == NULL ) - ||(pCertFile == NULL)||( pKeyFile == NULL ))) + if ( !pSSL ) + return NULL; + pListener = addListener( pName, pAddr ); + if ( !pListener ) + return NULL; + pListener->getVHostMap()->setSSLContext( pSSL ); + if ( pSSL->initSNI( pListener->getVHostMap() ) == -1 ) { - pListener = addListener( pName, pAddr ); - if ( pListener != NULL ) - { - if ( setupSSLContext( pListener, pCertFile, - pKeyFile, pCAFile, pCAPath, pCiphers, certChain, cv, renegProtect ) == -1 ) - { - m_listeners.remove( pListener ); - if ( pListener->getVHostMap()->getRef() > 0 ) - m_toBeReleasedListeners.add( pListener ); - else - { - pListener->stop(); - delete pListener; - } - pListener = NULL; - } - } + LOG_WARN(( "[SSL] TLS extension is not available in openssl library on this server, " + "server name indication is disabled, you will not able to use use per vhost" + " SSL certificates sharing one IP. Please upgrade your OpenSSL lib if you want to use this feature." + )); + } + return pListener; } @@ -1097,9 +1052,10 @@ int HttpServerImpl::initSampleServer() if ( addListener( "*:3080" ) == 0 ) { } - addSSLListener( "*:1443", "*:1443", - achBuf1, achBuf, NULL, NULL, - "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+SSLv2:+EXP" ); + SSLContext * pSSL = newSSLContext( NULL, achBuf1, achBuf, NULL, NULL, + "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+SSLv2:+EXP" , 0, 0, 0 ); + addSSLListener( "*:1443", "*:1443", pSSL ); + HttpVHost * pVHost = new HttpVHost( "vhost1" ); HttpVHost * pVHost2 = new HttpVHost( "vhost2" ); @@ -1336,13 +1292,13 @@ int HttpServer::test_main( ) printf( "sizeof( HttpConnection ) = %d, \n" "sizeof( HttpReq ) = %d, \n" "sizeof( HttpResp ) = %d, \n" - "sizeof( HttpIOLink ) = %d, \n" + "sizeof( NtwkIOLink ) = %d, \n" "sizeof( HttpVHost ) = %d, \n" "sizeof( LogTracker ) = %d, \n", sizeof( HttpConnection ), sizeof( HttpReq ), sizeof( HttpResp ), - sizeof( HttpIOLink ), + sizeof( NtwkIOLink ), sizeof( HttpVHost ), sizeof( LogTracker ) ); HttpFetch fetch; @@ -1385,35 +1341,11 @@ HttpListener* HttpServer::addListener( const char * pName, const char * pAddr ) } HttpListener* HttpServer::addSSLListener( const char * pName, - const char * pAddr, const char * pCertFile, - const char * pKeyFile, const char * pCAFile, - const char * pCAPath, - const char * pCiphers, int certChain, int cv ) + const char * pAddr, SSLContext * pCtx ) { - return m_impl->addSSLListener( pName, pAddr, - pCertFile, pKeyFile, pCAFile, pCAPath, pCiphers, certChain, cv ); + return m_impl->addSSLListener( pName, pAddr, pCtx ); } -int HttpServer::setupSSLContext( HttpListener *pListener, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, - const char * pCAPath, - const char * pCiphers, int certChain, int cv) -{ - return m_impl->setupSSLContext( pListener, pCertFile, pKeyFile, pCAFile, pCAPath, - pCiphers, certChain, cv); -} - - -int HttpServer::setupSSLContext( VHostMap *pMap, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, - const char * pCAPath, - const char * pCiphers, int certChain, int cv) -{ - return m_impl->setupSSLContext( pMap, pCertFile, pKeyFile, pCAFile, pCAPath, - pCiphers, certChain, cv); -} - - int HttpServer::removeListener( const char * pName ) { return m_impl->removeListener( pName ); @@ -1689,7 +1621,7 @@ SSLContext * HttpServerImpl::newSSLContext( SSLContext * pContext, const char *p delete pNewContext; } else if ( (pCAFile || pCAPath) && - !pNewContext->setCALocation( pCAFile, pCAPath, cv ) ) + !pNewContext->setCALocation( pCAFile, pCAPath, cv ) ) { LOG_ERR(( "[SSL] Failed to setup Certificate Authority " "Certificate File: '%s', Path: '%s', SSL error: %s", diff --git a/src/main/httpserver.h b/src/main/httpserver.h index 142ca71bb..e00f13cfa 100644 --- a/src/main/httpserver.h +++ b/src/main/httpserver.h @@ -64,20 +64,7 @@ class HttpServer : public TSingleton, public HttpLogSource int start(); int shutdown(); HttpListener* addListener( const char * pName, const char * pAddr ); - HttpListener* addSSLListener( const char * pName, const char * pAddr, - const char * pCertFile, - const char * pKeyFile, - const char * pCAFile, const char * pCAPath, - const char * pCiphers = NULL, - int certChain = 0, int cv = 0 ); - int setupSSLContext( HttpListener *pListener, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, - const char * pCAPath, const char * pCiphers = NULL, - int certChain = 0, int cv = 0); - int setupSSLContext( VHostMap *pMap, const char *pCertFile, - const char *pKeyFile, const char * pCAFile, - const char * pCAPath, const char * pCiphers = NULL, - int certChain = 0, int cv = 0 ); + HttpListener* addSSLListener( const char * pName, const char * pAddr, SSLContext *pSSL ); SSLContext * newSSLContext( SSLContext * pContext, const char *pCertFile, const char *pKeyFile, const char * pCAFile, const char * pCAPath, const char * pCiphers, int certChain, int cv, int renegProtect ); diff --git a/src/main/httpserverbuilder.cpp b/src/main/httpserverbuilder.cpp index 5d10593ab..ab564c154 100644 --- a/src/main/httpserverbuilder.cpp +++ b/src/main/httpserverbuilder.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -84,13 +85,13 @@ #include #include "plainconf.h" - +#include "sslpp/sslocspstapling.h" #define MAX_URI_LEN 1024 static const char * MISSING_TAG = "[%s] missing <%s>"; static const char * MISSING_TAG_IN = "[%s] missing <%s> in <%s>"; static const char * INVAL_TAG = "[%s] <%s> is invalid: %s"; -static const char * INVAL_TAG_IN = "[%s] invalid tag <%s> within <%s>!"; +//static const char * INVAL_TAG_IN = "[%s] invalid tag <%s> within <%s>!"; static const char * INVAL_PATH = "[%s] Path for %s is invalid: %s"; static const char * INACCESSIBLE_PATH = "[%s] Path for %s is not accessible: %s"; @@ -188,23 +189,23 @@ static long long getLongValue( const XmlNode * pNode, const char * pTag, } -static const char * getAccessFileName( const XmlNode * pNode, const char * pDefault ) -{ - const char * pValue = pNode->getChildValue( "accessFileName" ); - if ( !pValue ) - return pDefault; - else - { - if (( *pValue != '.' )||( strchr( pValue, '/' ))|| strlen( pValue ) > 14 ) - { - LOG_WARN(( "[%s] Access File Name must be less than 14 characters long, " - "start with '.' and not contain '/', use default name.", - getLogId() )); - return pDefault; - } - } - return pValue; -} +// static const char * getAccessFileName( const XmlNode * pNode, const char * pDefault ) +// { +// const char * pValue = pNode->getChildValue( "accessFileName" ); +// if ( !pValue ) +// return pDefault; +// else +// { +// if (( *pValue != '.' )||( strchr( pValue, '/' ))|| strlen( pValue ) > 14 ) +// { +// LOG_WARN(( "[%s] Access File Name must be less than 14 characters long, " +// "start with '.' and not contain '/', use default name.", +// getLogId() )); +// return pDefault; +// } +// } +// return pValue; +// } static void initExpires( const XmlNode * pExpires, ExpiresCtrl * pCtrl, const ExpiresCtrl * pDefault, HttpContext * pContext ) @@ -781,8 +782,6 @@ static HttpContext * addContext( HttpVHost * pVHost, int match, } } - - HttpContext * HttpServerBuilder::configContext( HttpVHost * pVHost, const char * pUri, int type, const char * pLocation, const char * pHandler, int allowBrowse ) @@ -1070,7 +1069,6 @@ static int getRedirectCode( const XmlNode * pContextNode, int &code, } - int HttpServerBuilder::configContext( HttpVHost * pVHost, const XmlNode* pContextNode ) { const char *pUri = NULL; @@ -1475,13 +1473,10 @@ int HttpServerBuilder::testDomainMod() } #endif - - - int HttpServerBuilder::configVHContextList( HttpVHost* pVHost, const XmlNode* pVhConfNode ) { - HttpContext *pRootContext = +// HttpContext *pRootContext = pVHost->addContext( "/", HandlerType::HT_NULL, pVHost->getDocRoot()->c_str(), NULL, 1 ); // pRootContext->setAutoIndex( pVHost->getRootContext().isAutoIndexOn() ); @@ -1509,6 +1504,52 @@ int HttpServerBuilder::configVHContextList( HttpVHost* pVHost, return 0; } +int HttpServerBuilder::configWebsocket( HttpVHost * pVHost, const XmlNode* pWebsocketNode ) +{ + const char *pUri = getTag(pWebsocketNode, "uri"); + const char *pAddress = getTag(pWebsocketNode, "address"); + char achVPath[MAX_PATH_LEN]; + char achRealPath[MAX_PATH_LEN]; + if ( pUri == NULL || pAddress == NULL ) + return -1; + + HttpContext* pContext = pVHost->getContext( pUri, 0 ); + if ( pContext == NULL ) + { + strcpy(achVPath, "$DOC_ROOT" ); + strcat(achVPath, pUri); + getAbsoluteFile( achRealPath, achVPath); + pContext = pVHost->addContext( pUri, HandlerType::HT_NULL, achRealPath, NULL, 1 ); + if ( pContext == NULL ) + return -1; + } + + GSockAddr gsockAddr; + gsockAddr.parseAddr( pAddress ); + pContext->setGSockAddr(gsockAddr); + return 0; +} + +int HttpServerBuilder::configVHWebsocketList( HttpVHost* pVHost, + const XmlNode* pVhConfNode ) +{ + const XmlNode* p0 = pVhConfNode->getChild("websocketlist"); + if ( p0 == NULL ) + p0 = pVhConfNode; + + const XmlNodeList* pList = p0->getChildren( "websocket"); + if ( pList ) + { + XmlNodeList::const_iterator iter; + for ( iter = pList->begin(); iter != pList->end(); ++iter ) + { + configWebsocket( pVHost, *iter ); + } + } + + return 0; +} + int HttpServerBuilder::configScriptHandler2( HttpVHost * pVHost, const XmlNodeList* pList, HttpMime * pHttpMime ) { @@ -2198,7 +2239,7 @@ int HttpServerBuilder::configVhost( HttpVHost* pVHost, pRootContext->inherit( NULL ); configVHContextList( pVHost, pVhConfNode ); - + configVHWebsocketList( pVHost, pVhConfNode ); return 0; } @@ -2542,7 +2583,7 @@ int HttpServerBuilder::addListener( const XmlNode* pNode, int isAdmin ) const char * pSecure = pNode->getChildValue( "secure" ); if ( pSecure ) secure = atoi( pSecure ); - HttpListener * pListener; + HttpListener * pListener = NULL; if ( secure == 0 ) { pListener = m_pServer->addListener(pName, pAddr); @@ -2555,77 +2596,15 @@ int HttpServerBuilder::addListener( const XmlNode* pNode, int isAdmin ) } else { - const char* pCertFile = getTag( pNode, "certFile" ); - if ( !pCertFile ) - { - break; - } - const char* pKeyFile = getTag( pNode, "keyFile" ); - if ( !pKeyFile ) - { - break; - } - char achCert[MAX_PATH_LEN]; - if ( getValidFile(achCert, pCertFile, "certificate file" ) != 0 ) - break; - char achKey[MAX_PATH_LEN]; - if ( getValidFile(achKey, pKeyFile, "key file") != 0 ) - break; - const char * pCiphers = pNode->getChildValue( "ciphers" ); - if ( !pCiphers ) - { - pCiphers = "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+SSLv2:+EXP"; - } - const char * pCAPath = pNode->getChildValue( "CACertPath" ); - const char * pCAFile = pNode->getChildValue( "CACertFile" ); - char achCAFile[MAX_PATH_LEN]; - char achCAPath[MAX_PATH_LEN]; - if ( pCAPath ) - { - if ( getValidPath( achCAPath, pCAPath, "CA Certificate path" ) != 0 ) - break; - pCAPath = achCAPath; - } - if ( pCAFile ) - { - if ( getValidFile( achCAFile, pCAFile, "CA Certificate file" ) != 0 ) - break; - pCAFile = achCAFile; - } - int cv = getLongValue( pNode, "clientVerify", 0, 3, 0 ); - - pListener = m_pServer->addSSLListener(pName, pAddr, achCert, - achKey, pCAFile, pCAPath, pCiphers, getLongValue( pNode, "certChain", 0, 1, 0 ), (cv!=0) ); + SSLContext * pSSLCtx = newSSLContext( pNode ); + if ( pSSLCtx ) + pListener = m_pServer->addSSLListener(pName, pAddr, pSSLCtx ); if ( pListener == NULL ) { LOG_ERR(( "[%s] failed to start SSL listener on address %s!", getLogId(), pAddr )); break; } - if ( cv > 0 ) - { - SSLContext * pSSL = pListener->getVHostMap()->getSSLContext(); - if ( pSSL ) - { - pSSL->setClientVerify( cv, getLongValue( pNode, "verifyDepth", 1, INT_MAX, 1 ) ); - pCAPath = pNode->getChildValue( "crlPath" ); - pCAFile = pNode->getChildValue( "crlFile" ); - if ( pCAPath ) - { - if ( getValidPath( achCAPath, pCAPath, "CRL path" ) != 0 ) - break; - pCAPath = achCAPath; - } - if ( pCAFile ) - { - if ( getValidFile( achCAFile, pCAFile, "CRL file" ) != 0 ) - break; - pCAFile = achCAFile; - } - if ( pCAPath || pCAFile ) - pSSL->addCRL( achCAFile, achCAPath ); - } - } } if ( HttpGlobals::s_children > 1 ) { @@ -3092,7 +3071,7 @@ int HttpServerBuilder::addExtProcessor( const XmlNode* pNode, const HttpVHost * struct passwd * pw = getUGid( pUser, pGroup, gid ); if ( pw ) { - if ( gid == -1 ) + if ( (int)gid == -1 ) gid = pw->pw_gid; if ((iType != EA_LOGGER)&&( ( pw->pw_uid < HttpGlobals::s_uidMin )|| ( gid < HttpGlobals::s_gidMin ))) @@ -3764,7 +3743,7 @@ int HttpServerBuilder::initSecurity( const XmlNode* pRoot ) { setThrottleLimit( ThrottleControl::getDefault(), pNode1, ThrottleControl::getDefault() ); - HttpIOLink::enableThrottle( (ThrottleControl::getDefault()->getOutputLimit() != INT_MAX) ); + NtwkIOLink::enableThrottle( (ThrottleControl::getDefault()->getOutputLimit() != INT_MAX) ); HttpGlobals::getClientCache()->resetThrottleLimit(); HttpGlobals::s_iConnsPerClientSoftLimit = getLongValue( pNode1, "softLimit", 1, INT_MAX, INT_MAX); @@ -3863,6 +3842,11 @@ int HttpServerBuilder::initServerBasic2( const XmlNode* pRoot ) " in the response header.", getLogId() )); } + HttpServer::getInstance().getServerContext().setGeoIP( + getLongValue( pRoot, "enableIpGeo", 0, 1, 0 ) ); + + HttpGlobals::s_useProxyHeader = getLongValue( pRoot, "useIpInProxyHeader", 0, 2, 0 ); + denyAccessFiles( NULL, ".ht*", 0 ); @@ -4286,6 +4270,44 @@ void HttpServerBuilder::enableCoreDump() #endif } +int HttpServerBuilder::configIpToGeo( const XmlNode * pNode ) +{ + const XmlNodeList* pList = pNode->getChildren( "geoipDB"); + if (( !pList )||( pList->size() == 0 )) + return 0; + IpToGeo * pIpToGeo = new IpToGeo(); + if ( !pIpToGeo ) + return -1; + XmlNodeList::const_iterator iter; + int succ = 0; + for ( iter = pList->begin(); iter != pList->end(); ++iter ) + { + XmlNode * p = *iter; + const char * pFile = p->getChildValue( "geoipDBFile" ); + char achBufFile[MAX_PATH_LEN]; + + if (( !pFile )|| + ( getValidFile(achBufFile, pFile, "GeoIP DB") != 0 )) + { + continue; + } + + if ( pIpToGeo->setGeoIpDbFile( achBufFile, p->getChildValue( "geoipDBCache" ) ) == 0 ) + succ = 1; + } + if ( succ ) + { + HttpGlobals::s_pIpToGeo = pIpToGeo; + } + else + { + delete pIpToGeo; + LOG_WARN(( "Failed to setup a valid GeoIP DB file, Geolocation is disable!" )); + } + return 0; +} + + int HttpServerBuilder::configServer( int reconfig ) { int ret; @@ -4365,6 +4387,13 @@ int HttpServerBuilder::configServer( int reconfig ) configScriptHandler2( NULL, pList, NULL ); } } + + p0 = m_pRoot->getChild( "ipToGeo" ); + if ( p0 ) + { + configIpToGeo( p0 ); + } + initAccessLog( *m_pServer, m_pRoot, 1 ); initVHosts( m_pRoot); initListenerVHostMap( m_pRoot, NULL ); @@ -4551,7 +4580,6 @@ LocalWorker * HttpServerBuilder::configRailsApp( int maxConns, const char * pRailsEnv, int maxIdle, const Env * pEnv, int runOnStart, const char * pRubyPath ) { - int ret ; char achFileName[MAX_PATH_LEN]; const char * pRailsRunner = m_sRailsRunner.c_str(); @@ -4729,7 +4757,6 @@ HttpContext * HttpServerBuilder::configRailsContext( int maxConns, const char * pRailsEnv, int maxIdle, const Env * pEnv, const char * pRubyPath ) { char achFileName[MAX_PATH_LEN]; - char achURI[MAX_URI_LEN]; if ( !m_railsDefault ) return NULL; @@ -4773,44 +4800,44 @@ LocalWorker * getPHPHandler( const char * pSuffix ) } -static int addPHPSuExec( HttpVHost * pVHost, int maxConn, - char * pSuffix, LocalWorker * pProto ) -{ - LocalWorker * pWorker; - char achAppName[1024]; - char achName[MAX_PATH_LEN]; - safe_snprintf( achAppName, 1024, "%sSu%s:", pVHost->getName(), pSuffix ); - - pWorker = (LocalWorker *)ExtAppRegistry::getApp( EA_LSAPI, achAppName ); - if ( !pWorker ) - { - pWorker = (LocalWorker *)ExtAppRegistry::addApp( EA_LSAPI, achAppName ); - if ( !pWorker ) - return 0; - safe_snprintf( achName, MAX_PATH_LEN, "uds://tmp/lshttpd/%s_Su%s.sock", - pVHost->getName(), pSuffix ); - pWorker->setURL( achName ); - LocalWorkerConfig& config = pWorker->getConfig(); - - config.setAppPath( pProto->getConfig().getCommand() ); - config.setBackLog( pProto->getConfig().getBackLog() ); - config.setSelfManaged( 0 ); - config.setMaxConns( maxConn ); - config.setKeepAliveTimeout( pProto->getConfig().getKeepAliveTimeout() ); - config.setPersistConn( 1 ); - config.setTimeout( pProto->getConfig().getTimeout() ); - config.setRetryTimeout( pProto->getConfig().getRetryTimeout() ); - config.setBuffering( pProto->getConfig().getBuffering() ); - config.setPriority( pProto->getConfig().getPriority() ); - config.setMaxIdleTime( 300 ); - config.setRLimits( pProto->getConfig().getRLimits() ); - config.clearEnv(); - config.addEnv( NULL ); - config.setVHost( pVHost ); - } - setPHPHandler( &pVHost->getRootContext(), pWorker, pSuffix ); - return 0; -} +// static int addPHPSuExec( HttpVHost * pVHost, int maxConn, +// char * pSuffix, LocalWorker * pProto ) +// { +// LocalWorker * pWorker; +// char achAppName[1024]; +// char achName[MAX_PATH_LEN]; +// safe_snprintf( achAppName, 1024, "%sSu%s:", pVHost->getName(), pSuffix ); +// +// pWorker = (LocalWorker *)ExtAppRegistry::getApp( EA_LSAPI, achAppName ); +// if ( !pWorker ) +// { +// pWorker = (LocalWorker *)ExtAppRegistry::addApp( EA_LSAPI, achAppName ); +// if ( !pWorker ) +// return 0; +// safe_snprintf( achName, MAX_PATH_LEN, "uds://tmp/lshttpd/%s_Su%s.sock", +// pVHost->getName(), pSuffix ); +// pWorker->setURL( achName ); +// LocalWorkerConfig& config = pWorker->getConfig(); +// +// config.setAppPath( pProto->getConfig().getCommand() ); +// config.setBackLog( pProto->getConfig().getBackLog() ); +// config.setSelfManaged( 0 ); +// config.setMaxConns( maxConn ); +// config.setKeepAliveTimeout( pProto->getConfig().getKeepAliveTimeout() ); +// config.setPersistConn( 1 ); +// config.setTimeout( pProto->getConfig().getTimeout() ); +// config.setRetryTimeout( pProto->getConfig().getRetryTimeout() ); +// config.setBuffering( pProto->getConfig().getBuffering() ); +// config.setPriority( pProto->getConfig().getPriority() ); +// config.setMaxIdleTime( 300 ); +// config.setRLimits( pProto->getConfig().getRLimits() ); +// config.clearEnv(); +// config.addEnv( NULL ); +// config.setVHost( pVHost ); +// } +// setPHPHandler( &pVHost->getRootContext(), pWorker, pSuffix ); +// return 0; +// } HttpContext * HttpServerBuilder::importWebApp( HttpVHost * pVHost, @@ -5014,7 +5041,7 @@ int HttpServerBuilder::initAdmin( const XmlNode * pNode ) pFcgiApp->getConfig().addEnv( "PHP_FCGI_MAX_REQUESTS=1000" ); snprintf( achPHPBin, MAX_PATH_LEN, "LSWS_EDITION=LiteSpeed Web Server/%s/%s", "Open", - VERSION ); + PACKAGE_VERSION ); pFcgiApp->getConfig().addEnv( achPHPBin ); RLimits limits; limits.setDataLimit( 500*1024*1024, 500*1024*1024 ); @@ -5095,7 +5122,7 @@ int HttpServerBuilder::initAdmin( const XmlNode * pNode ) strcpy( achPHPBin, m_achVhRoot ); strcat( achPHPBin, "html/" ); pVHostAdmin->setDocRoot( achPHPBin ); - HttpContext * pCtx = pVHostAdmin->addContext( "/", HandlerType::HT_NULL, achPHPBin, NULL, 1 ); + pVHostAdmin->addContext( "/", HandlerType::HT_NULL, achPHPBin, NULL, 1 ); getAbsoluteFile( achRootPath, "$SERVER_ROOT/docs/" ); HttpContext * pDocs = pVHostAdmin->addContext( "/docs/", @@ -5218,34 +5245,72 @@ void HttpServerBuilder::setServerRoot( const char * pRoot ) m_sServerRoot = pRoot; HttpGlobals::s_pServerRoot = m_sServerRoot.c_str(); } + +void HttpServerBuilder::configCRL( const XmlNode *pNode, SSLContext * pSSL ) +{ + char achCrlFile[MAX_PATH_LEN]; + char achCrlPath[MAX_PATH_LEN]; + const char * pCrlPath; + const char * pCrlFile; + pCrlPath = pNode->getChildValue( "crlPath" ); + pCrlFile = pNode->getChildValue( "crlFile" ); + if ( pCrlPath ) + { + if ( getValidPath( achCrlPath, pCrlPath, "CRL path" ) != 0 ) + return; + pCrlPath = achCrlPath; + } + if ( pCrlFile ) + { + if ( getValidFile( achCrlFile, pCrlFile, "CRL file" ) != 0 ) + return; + pCrlFile = achCrlFile; + } + if ( pCrlPath || pCrlFile ) + pSSL->addCRL( achCrlFile, achCrlPath ); + +} + SSLContext * HttpServerBuilder::newSSLContext( const XmlNode* pNode ) { + char achCert[MAX_PATH_LEN]; + char achKey [MAX_PATH_LEN]; + char achCAFile[MAX_PATH_LEN]; + char achCAPath[MAX_PATH_LEN]; + + const char* pCertFile; + const char* pKeyFile; + const char * pCiphers; + const char * pCAPath; + const char * pCAFile; + + SSLContext * pSSL; + int protocol; + int enableSpdy; + + int cv; - const char* pCertFile = getTag( pNode, "certFile" ); + pCertFile = getTag( pNode, "certFile" ); if ( !pCertFile ) { return NULL; } - const char* pKeyFile = getTag( pNode, "keyFile" ); + pKeyFile = getTag( pNode, "keyFile" ); if ( !pKeyFile ) { return NULL; } - char achCert[MAX_PATH_LEN]; if ( getValidFile(achCert, pCertFile, "certificate file" ) != 0 ) return NULL; - char achKey[MAX_PATH_LEN]; if ( getValidFile(achKey, pKeyFile, "key file") != 0 ) return NULL; - const char * pCiphers = pNode->getChildValue( "ciphers" ); + pCiphers = pNode->getChildValue( "ciphers" ); if ( !pCiphers ) { pCiphers = "ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:!SSLv2:+EXP"; } - const char * pCAPath = pNode->getChildValue( "CACertPath" ); - const char * pCAFile = pNode->getChildValue( "CACertFile" ); - char achCAFile[MAX_PATH_LEN]; - char achCAPath[MAX_PATH_LEN]; + pCAPath = pNode->getChildValue( "CACertPath" ); + pCAFile = pNode->getChildValue( "CACertFile" ); if ( pCAPath ) { if ( getValidPath( achCAPath, pCAPath, "CA Certificate path" ) != 0 ) @@ -5258,8 +5323,10 @@ SSLContext * HttpServerBuilder::newSSLContext( const XmlNode* pNode ) return NULL; pCAFile = achCAFile; } - int cv = 0; - SSLContext * pSSL = m_pServer->newSSLContext(NULL, achCert, + + cv = getLongValue( pNode, "clientVerify", 0, 3, 0 ); + + pSSL = m_pServer->newSSLContext(NULL, achCert, achKey, pCAFile, pCAPath, pCiphers, getLongValue( pNode, "certChain", 0, 1, 0 ), (cv!=0), getLongValue( pNode, "regenProtection", 0, 1, 1 ) ); if ( pSSL == NULL ) @@ -5269,5 +5336,56 @@ SSLContext * HttpServerBuilder::newSSLContext( const XmlNode* pNode ) return NULL; } + protocol = getLongValue( pNode, "sslProtocol", 1, 15, 15 ); + pSSL->setProtocol( protocol ); + + enableSpdy = getLongValue( pNode, "enableSpdy", 0, 3, 3 ); + if ( enableSpdy ) + if ( -1 == pSSL->enableSpdy( enableSpdy )) + LOG_ERR(( "[%s] SPDY can't be enabled [try to set to %d].", getLogId(), enableSpdy )); + + if ( cv ) + { + pSSL->setClientVerify( cv, getLongValue( pNode, "verifyDepth", 1, INT_MAX, 1 ) ); + configCRL( pNode, pSSL ); + } + + int enableStapling = getLongValue( pNode, "enableStapling", 0, 1, 0 ); + if (( enableStapling ) && (pCertFile != NULL)) + configStapling( pNode, pSSL, pCAFile, achCert); return pSSL; } + +int HttpServerBuilder::configStapling( const XmlNode* pNode, SSLContext *pSSL, const char* pCAFile, char* pachCert) +{ + SslOcspStapling* pSslOcspStapling = pSSL->getpStapling(); + if ( pSslOcspStapling == NULL ) + { + pSslOcspStapling = new SslOcspStapling; + pSSL->setpStapling ( pSslOcspStapling ) ; + pSslOcspStapling->setCertFile ( pachCert ); + if ( pCAFile ) + pSslOcspStapling->setCAFile( pCAFile ); + pSslOcspStapling->setRespMaxAge( getLongValue( pNode, "ocspRespMaxAge", 60, 360000, 3600 ) ); + const char* pResponder = pNode->getChildValue( "ocspResponder" ); + if ( pResponder ) + pSslOcspStapling->setOcspResponder ( pResponder ); + if (pSSL->initStapling() == -1) + { + LOG_ERR(( "[%s] OCSP Stapling can't be enabled [%s].", getLogId(), getStaplingErrMsg() )); + return -1; + } + const char* pCombineCAfile = pNode->getChildValue( "ocspCACerts" ); + char CombineCAfile[MAX_PATH_LEN]; + if ( pCombineCAfile ) + { + if ( getValidFile( CombineCAfile, pCombineCAfile, "Combine CA file" ) != 0 ) + return 0; + pCombineCAfile = CombineCAfile; + + pSslOcspStapling->setCombineCAfile ( pCombineCAfile ); + } + return 0; + } + return 0; +} diff --git a/src/main/httpserverbuilder.h b/src/main/httpserverbuilder.h index 52335c04c..718d8ca7c 100644 --- a/src/main/httpserverbuilder.h +++ b/src/main/httpserverbuilder.h @@ -84,7 +84,8 @@ class HttpServerBuilder { int configVHSecurity( HttpVHost* pVHost, const XmlNode* pVhConfNode ); int configVHIndexFile( HttpVHost* pVHost, const XmlNode* pVhConfNode ); void configVHChrootMode( HttpVHost * pVHost, const XmlNode * pNode ); - + int configVHWebsocketList( HttpVHost* pVHost, const XmlNode* pVhConfNode ); + const HttpHandler * getHandler( const HttpVHost * pVHost, const char * pType, const char * pHandler ); const HttpHandler * getHandler( const HttpVHost * pVHost, const XmlNode * pNode ); @@ -122,6 +123,8 @@ class HttpServerBuilder { HttpContext * configContext( HttpVHost * pVHost, const char * pUri, int type, const char * pLocation, const char * pHandler, int allowBrowse ); + + int configWebsocket( HttpVHost * pVHost, const XmlNode* pWebsocketNode ); int configContext( HttpVHost * pVHost, const XmlNode* pContextNode ); int configContextMime( HttpContext * pContext, const XmlNode * pContextNode ); @@ -184,8 +187,12 @@ class HttpServerBuilder { int denyAccessFiles( HttpVHost * pVHost, const char * pFile, int regex ); int offsetChroot( char * dest, const char *path ); + int configIpToGeo( const XmlNode * pNode ); + struct passwd * getUGid( const char * pUser, const char * pGroup, gid_t &gid ); + void configCRL( const XmlNode *pNode, SSLContext * pSSL ); + int configStapling( const XmlNode* pNode, SSLContext *pSSL, const char* pCAFile, char* pachCert); HttpServer * m_pServer; HttpVHost * m_pCurVHost; @@ -227,6 +234,7 @@ class HttpServerBuilder { , m_vhDomain( "" ) , m_vhAliases( "" ) , m_pRoot(NULL) + , m_sPlainconfPath ( "" ) , m_sAutoIndexURI( "/_autoindex/default.php" ) , m_iCrashGuard( 2 ) , m_enableCoreDump( 0 ) @@ -236,7 +244,6 @@ class HttpServerBuilder { , m_sUser( "nobody" ) , m_sGroup( "nobody" ) , m_iRailsEnv( 1 ) - , m_sPlainconfPath ( "" ) {}; ~HttpServerBuilder(); diff --git a/src/main/lshttpdmain.cpp b/src/main/lshttpdmain.cpp index cc359c87b..39a96c339 100644 --- a/src/main/lshttpdmain.cpp +++ b/src/main/lshttpdmain.cpp @@ -262,7 +262,6 @@ void LshttpdMain::onGuardTimer() int LshttpdMain::processAdminCmd( char * pCmd, char * pEnd, int &apply ) { - char *p; if ( strncasecmp( pCmd, "reload:", 7 ) == 0 ) { apply = 1; @@ -470,8 +469,6 @@ int LshttpdMain::processAdminBuffer( char * p, char * pEnd ) void LshttpdMain::writeSysStats() { - static char achPath[] = "PATH=/bin:/usr/bin"; - int pid; char achStatsFile[256] = ""; char achTmpStatsFile[256]; if ( HttpGlobals::s_psChroot ) @@ -485,10 +482,12 @@ void LshttpdMain::writeSysStats() int fd = open( achTmpStatsFile, O_WRONLY | O_CREAT, 0644 ); if ( fd == -1 ) LOG_ERR(( "Failed to create system statistic report file: %s", achTmpStatsFile )); - writeProcessData( fd ); - close( fd ); - rename( achTmpStatsFile, achStatsFile ); - + else + { + writeProcessData( fd ); + close( fd ); + rename( achTmpStatsFile, achStatsFile ); + } } void LshttpdMain::writeProcessData( int fd ) @@ -930,7 +929,6 @@ int LshttpdMain::init(int argc, char * argv[]) int LshttpdMain::main( int argc, char * argv[] ) { - int ret; argv0 = argv[0]; VMemBuf::initAnonPool(); @@ -943,7 +941,7 @@ int LshttpdMain::main( int argc, char * argv[] ) allocatePidTracker(); m_pServer->initAdns(); - ret = m_pServer->test_main( ); + m_pServer->test_main( ); } else #endif @@ -1132,7 +1130,7 @@ int LshttpdMain::cleanUp( int pid, char * pBB ) int LshttpdMain::checkRestartReq( ) { ChildProc * pProc; - LinkedObj * pPrev = m_childrenList.head(); +// LinkedObj * pPrev = m_childrenList.head(); pProc = (ChildProc *)m_childrenList.begin(); while( pProc ) { @@ -1158,7 +1156,7 @@ int LshttpdMain::checkRestartReq( ) gracefulRestart(); return 0; } - pPrev = pProc; +// pPrev = pProc; pProc = (ChildProc *)pProc->next(); } return 0; @@ -1392,21 +1390,21 @@ void LshttpdMain::processSignal() LOG_NOTICE(( "SIGTERM received, stop server...")); s_iRunning = 0; } - if ( HttpSignals::gotSigUsr1() ) + if ( HttpSignals::gotSigUsr1() || HttpSignals::gotSigHup() ) { LOG_NOTICE(( "Server Restart Request via Signal...")); gracefulRestart(); } - if ( HttpSignals::gotSigHup() ) - { - LOG_NOTICE(( "SIGHUP received, Reloading configuration file...")); - if ( reconfig() == -1) - { - s_iRunning = 0; - return; - } - applyChanges(); - } +// if ( HttpSignals::gotSigHup() ) +// { +// LOG_NOTICE(( "SIGHUP received, Reloading configuration file...")); +// if ( reconfig() == -1) +// { +// s_iRunning = 0; +// return; +// } +// applyChanges(); +// } if ( HttpSignals::gotSigChild() ) waitChildren(); HttpSignals::resetEvents(); diff --git a/src/main/plainconf.cpp b/src/main/plainconf.cpp index 2c796a2ba..a2b6f4da7 100644 --- a/src/main/plainconf.cpp +++ b/src/main/plainconf.cpp @@ -259,9 +259,9 @@ static plainconfKeywords sKeywords[] = { {"vhroot", ""}, {"vhtemplate", ""}, {"virtualhost", ""}, + {"websocket", ""}, {"workingdir", ""}, - }; namespace plainconf { diff --git a/src/socket/gsockaddr.cpp b/src/socket/gsockaddr.cpp index ad92c694a..b2344ed52 100644 --- a/src/socket/gsockaddr.cpp +++ b/src/socket/gsockaddr.cpp @@ -129,6 +129,54 @@ const char * parseURL( const char * pURL, int* domain ) return pURL; } +//Only deal with "http://" and "https://" cases +//ie: "http://www.litespeedtech.com/about-litespeed-technologies-inc.html" +// "http://www.litespeedtech.com" +int GSockAddr::setHttpUrl ( const char *pHttpUrl, const int len ) +{ + const char *httpurl = pHttpUrl; + char url[1024] = {0}; + const char *p, *q; + int endPos = 0; + int iHttps = 0; + + if ( ((*httpurl++ | 0x20) != 'h') || + ((*httpurl++ | 0x20) != 't') || + ((*httpurl++ | 0x20) != 't') || + ((*httpurl++ | 0x20) != 'p') ) + return -1; + + if ( (*httpurl | 0x20) == 's' ) + { + iHttps = 1; + ++httpurl; + } + + if ( *httpurl == ':' ) + p = httpurl + 3; + else + return -1; + + q = strchr ( p, '/' ); + if ( q ) + endPos = q - p; + else + endPos = pHttpUrl + len - p; + + memcpy(url, p, endPos); + url[endPos] = 0; + + //If not contain ":", add it and default port + if ( strchr(url, ':') == NULL ) + { + if ( iHttps ) + memcpy( url + endPos, ":443\0", 5); + else + memcpy( url + endPos, ":80\0", 4); + } + + return set(url, NO_ANY | DO_NSLOOKUP); +} int GSockAddr::set( const char * pURL, int tag ) { diff --git a/src/socket/gsockaddr.h b/src/socket/gsockaddr.h index e49b7e66b..8f55fbd0c 100644 --- a/src/socket/gsockaddr.h +++ b/src/socket/gsockaddr.h @@ -103,6 +103,7 @@ class GSockAddr void set( const in6_addr* addr, const in_port_t port, uint32_t flowinfo = 0 ); int set( const char * pURL, int tag ); int set( int family, const char * pURL, int tag = 0 ); + int setHttpUrl ( const char *pHttpUrl, const int len ); int parseAddr( const char * pString ); /** return the address in string format. */ static const char * ntop( const struct sockaddr * pAddr, char * pBuf, int len ); diff --git a/src/spdy/CMakeLists.txt b/src/spdy/CMakeLists.txt new file mode 100644 index 000000000..6ef7b5d73 --- /dev/null +++ b/src/spdy/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8) + + +########### next target ############### + +SET(spdy_STAT_SRCS +spdyprotocol.cpp +spdyconnection.cpp +spdystream.cpp +spdyzlibfilter.cpp +spdystreampool.cpp +spdydebug.cpp +) + +add_library(spdy STATIC ${spdy_STAT_SRCS}) + diff --git a/src/spdy/Makefile.am b/src/spdy/Makefile.am new file mode 100755 index 000000000..11838e8aa --- /dev/null +++ b/src/spdy/Makefile.am @@ -0,0 +1,8 @@ +noinst_LIBRARIES = libspdy.a + +INCLUDES = -I$(top_srcdir)/src +libspdy_a_METASOURCES = AUTO + +libspdy_a_SOURCES = spdyprotocol.cpp spdyconnection.cpp spdystream.cpp spdyzlibfilter.cpp spdystreampool.cpp + +noinst_HEADERS = diff --git a/src/spdy/Makefile.in b/src/spdy/Makefile.in new file mode 100644 index 000000000..eea7a5bce --- /dev/null +++ b/src/spdy/Makefile.in @@ -0,0 +1,493 @@ +# Makefile.in generated by automake 1.12.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2012 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = src/spdy +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/ax_check_zlib.m4 \ + $(top_srcdir)/ax_check_openssl.m4 \ + $(top_srcdir)/ax_path_lib_pcre.m4 \ + $(top_srcdir)/ax_lib_expat.m4 $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libspdy_a_AR = $(AR) $(ARFLAGS) +libspdy_a_LIBADD = +am_libspdy_a_OBJECTS = spdyprotocol.$(OBJEXT) spdyconnection.$(OBJEXT) \ + spdystream.$(OBJEXT) spdyzlibfilter.$(OBJEXT) \ + spdystreampool.$(OBJEXT) +libspdy_a_OBJECTS = $(am_libspdy_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(libspdy_a_SOURCES) +DIST_SOURCES = $(libspdy_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_CFLAGS = @EXPAT_CFLAGS@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXPAT_VERSION = @EXPAT_VERSION@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +OPENLSWS_ADMIN = @OPENLSWS_ADMIN@ +OPENLSWS_ADMINSSL = @OPENLSWS_ADMINSSL@ +OPENLSWS_DISABLE_RPATH = @OPENLSWS_DISABLE_RPATH@ +OPENLSWS_EMAIL = @OPENLSWS_EMAIL@ +OPENLSWS_GROUP = @OPENLSWS_GROUP@ +OPENLSWS_LIBDIR = @OPENLSWS_LIBDIR@ +OPENLSWS_PASSWORD = @OPENLSWS_PASSWORD@ +OPENLSWS_USER = @OPENLSWS_USER@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_LIBS = @PCRE_LIBS@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = libspdy.a +INCLUDES = -I$(top_srcdir)/src +libspdy_a_METASOURCES = AUTO +libspdy_a_SOURCES = spdyprotocol.cpp spdyconnection.cpp spdystream.cpp spdyzlibfilter.cpp spdystreampool.cpp +noinst_HEADERS = +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/spdy/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/spdy/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libspdy.a: $(libspdy_a_OBJECTS) $(libspdy_a_DEPENDENCIES) $(EXTRA_libspdy_a_DEPENDENCIES) + -rm -f libspdy.a + $(libspdy_a_AR) libspdy.a $(libspdy_a_OBJECTS) $(libspdy_a_LIBADD) + $(RANLIB) libspdy.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdyconnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdyprotocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdystream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdystreampool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdyzlibfilter.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +cscopelist: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES cscopelist ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/spdy/spdyconnection.cpp b/src/spdy/spdyconnection.cpp new file mode 100644 index 000000000..c71f52c7b --- /dev/null +++ b/src/spdy/spdyconnection.cpp @@ -0,0 +1,1071 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "spdyconnection.h" +#include "spdystream.h" +#include "spdystreampool.h" +#include +#include +#include + +#include "edio/inputstream.h" +#include + +static hash_key_t int_hash( const void * p ) +{ + return ( int )(long)p; +} + +static int int_comp( const void * pVal1, const void * pVal2 ) +{ + return ( int )(long)pVal1 - ( int )(long)pVal2; +} + +static inline void appendNbo4Bytes( LoopBuf * pBuf, uint32_t val ) +{ + pBuf->append( val >> 24 ); + pBuf->append( ( val >> 16 ) & 0xff ); + pBuf->append( ( val >> 8 ) & 0xff ); + pBuf->append( val & 0xff ); +} + +static inline void append4Bytes( LoopBuf * pBuf, const char * val ) +{ + pBuf->append( *val++ ); + pBuf->append( *val++ ); + pBuf->append( *val++ ); + pBuf->append( *val ); +} + +SpdyConnection::SpdyConnection() + : m_bufInput( 4096 ) + , m_deflator() + , m_inflator() + , m_uiServerStreamID( 2 ) + , m_uiLastPingID( 0 ) + , m_uiLastStreamID( 0 ) + , m_uiGoAwayId( 0 ) + , m_mapStream( 50, int_hash, int_comp ) + , m_flag( 0 ) + , m_iServerInitWindowSize( 5*1024*1024 ) + , m_iServerMaxStreams( 500 ) + , m_iClientInitWindowSize( 65536 ) + , m_iClientMaxStreams( 100 ) + , m_tmIdleBegin( 0 ) +{ +} + +int SpdyConnection::init( HiosProtocol ver ) +{ + m_deflator.init( 0, ver ); + m_inflator.init( 1, ver ); + m_uiLastStreamID = 0; + m_bVersion = ver + 1; + if ( ver == HIOS_PROTO_SPDY3 ) + m_iClientInitWindowSize = 65536; + else + m_iClientInitWindowSize = 1024 * 1024 * 1024; //For SPDY2, there is no flow control, set it to a large value + m_iServerMaxStreams = 500; + m_iClientMaxStreams = 100; + + m_tmIdleBegin = 0; + m_iCurrentFrameRemain = -8; + m_pcurrentSpdyHeader = (SpdyFrameHeader*)m_SpdyHeaderMem; + return 0; +} + + +int SpdyConnection::onInitConnected() +{ + m_state = HIOS_CONNECTED; + setOS( getStream() ); + getStream()->continueRead(); + sendSettings(m_iServerMaxStreams, m_iServerInitWindowSize); + return 0; +} + +SpdyConnection::~SpdyConnection() +{ +} + +SpdyConnection& SpdyConnection::operator=( const SpdyConnection & other ) +{ + return *this; +} + + +int SpdyConnection::onReadEx() +{ + int ret = onReadEx2(); + if ( !isEmpty() ) + flush(); + return ret; +} + +int SpdyConnection::onReadEx2() +{ + int n = 0, avaiLen = 0; + while( true ) + { + if ( m_bufInput.available() < 500 ) + m_bufInput.guarantee( 1024 ); + avaiLen = m_bufInput.contiguous(); + n = getStream()->read( m_bufInput.end(), avaiLen ); + //if ( D_ENABLED( DL_LESS ) ) + //{ + // LOG_D(( getLogger(), "[%s] getStream()->read(), availLen = %d, ret = %d", + // getLogId(), avaiLen, n )); + //} + + if ( n == -1 ) + { + // must start to close connection + // must turn off READING event in the meantime + getStream()->suspendRead(); + onCloseEx(); + return -1; + } + else if ( n == 0 ) + break; + m_bufInput.used( n ); + while( !m_bufInput.empty() ) + { + if ( m_iCurrentFrameRemain < 0 ) + { + if ( m_bufInput.size() < 8 ) + break; + m_bufInput.moveTo((char*)m_pcurrentSpdyHeader, 8); + m_iCurrentFrameRemain = m_pcurrentSpdyHeader->getLength(); + } + if ( m_pcurrentSpdyHeader->isControlFrame() ) + { + if ( m_iCurrentFrameRemain > m_bufInput.size() ) + break; + if ( processControlFrame(m_pcurrentSpdyHeader) == -1 ) + { + doGoAway( SPDY_GOAWAY_PROTOCOL_ERROR ); + return -1; + + } + if ( m_iCurrentFrameRemain > 0 ) + m_bufInput.pop_front( m_iCurrentFrameRemain ); + m_iCurrentFrameRemain = -8; + } + else + { + processDataFrame( m_pcurrentSpdyHeader ); + if ( m_iCurrentFrameRemain == 0 ) + m_iCurrentFrameRemain = -8; + } + } + } + return 0; +} + +int SpdyConnection::processControlFrame( SpdyFrameHeader* pHeader) +{ + static int extraHeaderLen[2][11] = + { + { 0, 10, 6, 8, 4, 0, 4, 4, 6, 8, 8 }, + { 0, 10, 4, 8, 4, 0, 4, 8, 4, 8, 8 } + } ; + int extraHeader = 8; + if ( m_bVersion != pHeader->getVersion() ) + { + //Spdy version does not match, + LOG_INFO(( "[%s] Protocol error, session is SPDY%d, frame " + "header version is SPDY%d, go away!", + getLogId(), m_bVersion, pHeader->getVersion() )); + return -1; + } + if(pHeader->getType() <= 10) + extraHeader = extraHeaderLen[m_bVersion -2][pHeader->getType()]; + if(extraHeader > m_iCurrentFrameRemain) + extraHeader = m_iCurrentFrameRemain; + memset((char*)pHeader + 8, 0, 10); + m_bufInput.moveTo((char*)pHeader + 8, extraHeader); + m_iCurrentFrameRemain -= extraHeader; + printLogMsg(pHeader); + switch ( pHeader->getType() ) + { + case SPDY_FRAME_SYN_STREAM: + return processSynStreamFrame( pHeader ); + case SPDY_FRAME_HEADERS: + return extractCompressedData(); + case SPDY_FRAME_SYN_REPLY: + return extractCompressedData(); + case SPDY_FRAME_RST_STREAM: + processRstFrame( pHeader ); + break; + case SPDY_FRAME_GOAWAY: + processGoAwayFrame( pHeader ); + break; + case SPDY_FRAME_SETTINGS: + return processSettingFrame( pHeader ); + case SPDY_FRAME_PING: + processPingFrame( pHeader ); + break; + case SPDY_FRAME_WINDOW_UPDATE: + processWindowUpdateFrame( pHeader ); + break; + case SPDY_FRAME_CREDENTIAL: + break; + default: + LOG_INFO(( "[%s] SPDY%d protocol error, unknown frame type: %d, go away!", + getLogId(), m_bVersion, pHeader->getVersion() )); + //break protocol, bad client + return -1; + } + return 0; +} + +void SpdyConnection::printLogMsg( SpdyFrameHeader* pHeader ) +{ + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] Received %s, size: %d, D0:%d, D1:%d\n", + getLogId(),getFrameName(pHeader->getType()), pHeader->getLength(), + pHeader->getHboData( 0 ), pHeader->getHboData( 1 )) ); + } +} + +int SpdyConnection::processSettingFrame( SpdyFrameHeader * pHeader ) +{//process each setting ID/value pair + static char cpTemp[100]; + static const char* cpEntryNames[] = + { "", + "SPDY_SETTINGS_UPLOAD_BANDWIDTH = ", + "SPDY_SETTINGS_DOWNLOAD_BANDWIDTH = ", + "SPDY_SETTINGS_ROUND_TRIP_TIME = ", + "SPDY_SETTINGS_MAX_CONCURRENT_STREAMS = ", + "SPDY_SETTINGS_CURRENT_CWND = ", + "SPDY_SETTINGS_DOWNLOAD_RETRANS_RATE = ", + "SPDY_SETTINGS_INITIAL_WINDOW_SIZE = " }; + uint32_t iEntryID, iEntryValue; + SpdySettingPairs settingPairs; + unsigned char ucEntryFlags; + int iEntries = pHeader->getHboData( 0 ); + unsigned char ucflags = pHeader->getFlags(); + if ( m_iCurrentFrameRemain != 8 * iEntries ) + { + LOG_INFO(( getLogger(), "[%s] bad SETTING frame, frame size does not match, ignore.", + getLogId() )); + return 0; + } + if ( D_ENABLED( DL_LESS ) ) + { + snprintf( cpTemp, 100, "SPDY SETTINGS: Version:%d, Flags:%d, Number of Entries:%d\n", + m_bVersion, ucflags, iEntries); + m_bufInflate.clear(); + m_bufInflate.append(cpTemp); + } + + + for( int i = 0; i < iEntries; i++) + { + m_bufInput.moveTo( (char*)&settingPairs, 8); + if ( m_bVersion == 3 ) + settingPairs.swapID(); + ucEntryFlags = settingPairs.getFlags(); + iEntryID = settingPairs.getID(); + iEntryValue = settingPairs.getValue(); + if ( D_ENABLED( DL_LESS ) ) + { + m_bufInflate.append(cpEntryNames[iEntryID]); + sprintf( cpTemp, "%d, Flags=%d\n", iEntryValue, ucEntryFlags); + m_bufInflate.append(cpTemp); + } + switch( iEntryID ) + { + case SPDY_SETTINGS_INITIAL_WINDOW_SIZE: + m_iClientInitWindowSize = iEntryValue ; + break; + case SPDY_SETTINGS_MAX_CONCURRENT_STREAMS: + m_iClientMaxStreams = iEntryValue ; + break; + default: + break; + } + } + m_iCurrentFrameRemain = 0; + if ( D_ENABLED( DL_LESS ) ) + { + m_bufInflate.append( '\0' ); + LOG_D(( getLogger(), "[%s] %s", + getLogId(), m_bufInflate.begin() ) ); + } + return 0; +} + +int SpdyConnection::processWindowUpdateFrame( SpdyFrameHeader * pHeader ) +{ + int32_t id = pHeader->getHboData(0); + int32_t delta = pHeader->getHboData(1); + StreamobjpMap::iterator it = m_mapStream.find(( void* ) id ); + if ( it != m_mapStream.end() ) + { + SpdyStream * pStream = it.second(); + int32_t current = pStream->getWindowOut(); + if ( pStream->isFlowCtrl() ) + { + pStream->adjWindowOut( delta ); + if (( current >= 0 )&&( pStream->getWindowOut() < 0 )) + { + //window overflow + resetStream( it, SPDY_RST_STREAM_FLOW_CONTROL_ERROR ); + } + else if (( pStream->isWantWrite() )&& ( pStream->getWindowOut() > 0 )) + getStream()->continueWrite(); + } + } + return 0; +} + + +int SpdyConnection::processRstFrame( SpdyFrameHeader* pHeader ) +{ + StreamobjpMap::iterator it = m_mapStream.find(( void* ) pHeader->getHboData(0) ); + if ( it == m_mapStream.end() ) + return 0; + SpdyStream* pSpdyStream = it.second(); + pSpdyStream->setFlag( HIO_FLAG_PEER_RESET, 1 ); + recycleStream( it ); + + return 0; +} + +void SpdyConnection::skipRemainData() +{ + int len = m_bufInput.size(); + if ( len > m_iCurrentFrameRemain ) + len = m_iCurrentFrameRemain; + m_bufInput.pop_front( len ); + m_iCurrentFrameRemain -= len; +} + +int SpdyConnection::processDataFrame( SpdyFrameHeader* pHeader ) +{ + uint32_t streamID = pHeader->getDataStreamId(); + SpdyStream* pSpdyStream = findStream( streamID ); + if ( pSpdyStream == NULL ) + { + skipRemainData(); + sendRstFrame( streamID, SPDY_RST_STREAM_INVALID_STREAM ); + return 0; + } + if ( pSpdyStream->isPeerShutdown() ) + { + skipRemainData(); + sendRstFrame( streamID, SPDY_RST_STREAM_ALREADY_CLOSED ); + return 0; + } + while( m_iCurrentFrameRemain > 0 ) + { + int len = m_bufInput.blockSize(); + if ( len == 0 ) + break; + if ( len > m_iCurrentFrameRemain ) + { + len = m_iCurrentFrameRemain; + } + m_iCurrentFrameRemain -= len; + pSpdyStream->appendReqData( m_bufInput.begin(), len, + m_iCurrentFrameRemain ? 0 : pHeader->getFlags() ); + m_bufInput.pop_front( len ); + } + + if ( isSpdy3() && !pSpdyStream->isPeerShutdown() ) + { + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] processDataFrame() ID: %d, input window size: %d ", + getLogId(), streamID, pSpdyStream->getWindowIn() ) ); + } + + if ( pSpdyStream->getWindowIn() < m_iServerInitWindowSize / 2 ) + { + sendWindowUpdateFrame( streamID, m_iServerInitWindowSize / 2 ); + pSpdyStream->adjWindowIn( m_iServerInitWindowSize / 2 ); + } + } + return 0; +} + +int SpdyConnection::processSynStreamFrame(SpdyFrameHeader* pHeader ) +{ + int headerCount; + int ret; + int n = 0; + int priority; + SpdyStream* pStream; + uint32_t id = pHeader->getHboData( 0 ); + if ( m_flag & SPDY_CNN_FLAG_GOAWAY ) + { + return 0; + } + + if ( id <= m_uiLastStreamID ) + { + sendRstFrame( id, SPDY_RST_STREAM_PROTOCOL_ERROR ); + LOG_INFO(( "[%s] Protocol error, SYN_STREAM ID: %d is less the" + " previously received stream ID: %d, cannot keep" + " decompression state in sync, go away!", + getLogId(), id, m_uiLastStreamID )); + + return -1; + } + m_uiLastStreamID = id; + n = extractCompressedData(); + if( n < 0) + { + return -1; + } + if ( m_mapStream.size() >= (uint)m_iServerMaxStreams ) + { + sendRstFrame( id, SPDY_RST_STREAM_REFUSED_STREAM ); + return 0; + } + ret = parseHeaders( m_bufInflate.begin(), n, headerCount ); + if ( ret > 0 ) + { + if ( ret < SPDY_RST_STREAM_NUM_STATUS_CODES ) + sendRstFrame( id, (SpdyRstErrorCode)ret ); + return 0; + } + if ( ret == -2 ) + { //method, url, and version not present together + //Need to send HTTP 400 BAD REQUEST reply. + append400BadReqReply( id ); + return 0; + } + + priority = (( uint8_t* )pHeader)[16] >> (8 - m_bVersion ); + pStream = getNewStream( id, priority, pHeader->getFlags() ); + if ( pStream ) + { + appendReqHeaders( pStream, headerCount ); + pStream->onInitConnected(); + if ( pStream->getState() == HIOS_DISCONNECTED ) + recycleStream( pStream->getStreamID() ); + } + else + { + sendRstFrame( id, SPDY_RST_STREAM_INTERNAL_ERROR ); + } + return 0; +} + +int SpdyConnection::extractCompressedData() +{ + int n = 0, n1 = 0;; + m_bufInflate.clear(); + int iDatalen = ( m_bufInput.blockSize() < m_iCurrentFrameRemain)? ( m_bufInput.blockSize()):(m_iCurrentFrameRemain); + while ( iDatalen > 0 ) + { + n = m_inflator.spdyHeaderInflate( m_bufInput.begin(), iDatalen, m_bufInflate ); + if ( n < 0) + { + logDeflateInflateError( n, 0); + return -1; + } + m_bufInput.pop_front(iDatalen); + m_iCurrentFrameRemain -= iDatalen; + iDatalen = m_iCurrentFrameRemain; + n1 += n; + } + return n1; + +} + +static int IstheKey( const char * str1, int Length1, const char * str2, int Length2 ) +{ + if( ( Length1 == Length2 ) && ( strncmp( str1, str2, Length1 ) == 0 )) + return 1; + else + return 0; +} + +int SpdyConnection::checkReqline( char* pName, int ilength, uint8_t& flags) +{ + static const char* pReqs[2][3] = + { + { "method", "url", "version" }, + { ":method", ":path", ":version" } + }; + static const int pReqslen[2][3] = + { + { 6, 3, 7 }, + { 7, 5, 8 } + }; + int bitflag = 1, nv = m_bVersion -2; + for(int i=0; i<3; i++) + { + if( ((flags & bitflag) ==0) && IstheKey(( const char* )pName, ilength, pReqs[nv][i], pReqslen[nv][i] ) ) + { + pName += (ilength + (nv+1)*2); + m_NameValuePairListReqline[i].pValue = pName; + if(nv == 0) + m_NameValuePairListReqline[i].ValueLen = beReadUint16( (unsigned char*)pName - 2 ); + else + m_NameValuePairListReqline[i].ValueLen = beReadUint32( (unsigned char*)pName - 4 ); + flags |= bitflag; + return (m_NameValuePairListReqline[i].ValueLen + ilength + (nv+1)*2); + } + bitflag = bitflag << 1; + } + return 0; +} + +int SpdyConnection::parseHeaders( char* pHeader, int ilength, int &NVPairCnt ) +{ + uint8_t flags = 0; + unsigned char* buff = ( unsigned char* )pHeader; + unsigned char* buffEnd = buff + ilength; + uint32_t NameCount, theLength; + int n = 0; + + NVPairCnt = 0; + + NameCount = (m_bVersion == 3)? (beReadUint32Adv( buff )):(beReadUint16Adv( buff )); + if ( NameCount == 0 ) + return 0; + + if(NameCount > 100) + return SPDY_RST_STREAM_FRAME_TOO_LARGE; + + for ( uint i = 0; i < NameCount; i++ ) + { + if( (theLength = (m_bVersion == 3)? (beReadUint32Adv( buff )):(beReadUint16Adv( buff ))) == 0) + { + return SPDY_RST_STREAM_PROTOCOL_ERROR; + } + if ( buff + theLength > buffEnd ) + return SPDY_RST_STREAM_PROTOCOL_ERROR; + if( (flags^0x7) && ((n = checkReqline((char*)buff, theLength, flags))>0 )) + buff += n; + else + { + int needThisHeader = 1; + if( m_bVersion == 3 ) + {//Hack here :host ==> host + if (theLength == 5 && + strncmp(( const char* )buff, ":host", 5) == 0) + { + -- theLength; + ++ buff ; + } + else if ( (*(char*)buff) == ':') + { + needThisHeader = 0; + } + } + m_NameValuePairList[NVPairCnt].nameLen = theLength; + m_NameValuePairList[NVPairCnt].pName = ( char* )buff; + + buff += theLength; + theLength = (m_bVersion == 3)? (beReadUint32Adv( buff )):(beReadUint16Adv( buff )); + if ( buff + theLength > buffEnd ) + return SPDY_RST_STREAM_PROTOCOL_ERROR; + if (needThisHeader) + { + replaceZero( (char*)buff, theLength ); + m_NameValuePairList[NVPairCnt].ValueLen = theLength; + m_NameValuePairList[NVPairCnt++].pValue = ( char* )buff; + } + buff += theLength; + } + } + if ( flags^0x7 ) + { //method, url, and version not present together + return -2; + } + + return 0; +} + +void SpdyConnection::replaceZero( char* pValue, int ilength ) +{ + char *pEnd = pValue + ilength; + while ( (pValue) && (pValue < pEnd) ) + { + pValue = (char*) memchr(pValue, 0, ilength); + if(pValue != NULL) + { + *pValue++ = ','; + ilength = pEnd - pValue; + } + } +} +int SpdyConnection::appendReqHeaders( SpdyStream* pStream, int NVPairCnt ) +{ + pStream->getBufIn()->guarantee( m_bufInflate.size() ); + for( int i = 0; i < 3; i++ ) + { + pStream->appendInputData( m_NameValuePairListReqline[i].pValue, m_NameValuePairListReqline[i].ValueLen); + if( i == 2 ) + { + pStream->appendInputData( '\r' ); + pStream->appendInputData( '\n' ); + } + else + { + pStream->appendInputData( ' ' ); + } + } + for( int i = 0; i < NVPairCnt; i++ ) + { + pStream->appendInputData( m_NameValuePairList[i].pName, m_NameValuePairList[i].nameLen ); + pStream->appendInputData( ':' ); + pStream->appendInputData( ' ' ); + pStream->appendInputData( m_NameValuePairList[i].pValue, m_NameValuePairList[i].ValueLen ); + pStream->appendInputData( '\r' ); + pStream->appendInputData( '\n' ); + } + pStream->appendInputData( '\r' ); + pStream->appendInputData( '\n' ); + return 0; + +} + +SpdyStream* SpdyConnection::getNewStream( uint32_t uiStreamID, int iPriority, uint8_t ubSpdy_Flags) +{ + SpdyStream* pStream; + NtwkIOLink * pLink; + + HttpConnection * pConn = HttpConnPool::getConnection(); + if ( !pConn ) + return NULL; + pLink = dynamic_cast(getStream() ); + pConn->setNtwkIOLink( pLink ); + pStream = new SpdyStream(); + //pStream = SpdyStreamPool::getSpdyStream(); + m_mapStream.insert(( void* )uiStreamID, pStream ); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] getNewStream(), ID: %d, stream map size: %d ", + getLogId(), uiStreamID, m_mapStream.size() ) ); + } + pStream->init( uiStreamID, iPriority, this, ubSpdy_Flags, pConn ); + pStream->setProtocol( pLink->getProtocol() ); + if ( m_bVersion == 3 ) + pStream->setFlag( HIO_FLAG_FLOWCTRL, 1 ); + return pStream; +} + + +void SpdyConnection::recycleStream( uint32_t uiStreamID ) +{ + StreamobjpMap::iterator it = m_mapStream.find(( void* ) uiStreamID ); + if ( it == m_mapStream.end() ) + return; + recycleStream( it ); +} + + +void SpdyConnection::recycleStream( StreamobjpMap::iterator it ) +{ + SpdyStream* pSpdyStream = it.second(); + m_mapStream.erase( it ); + pSpdyStream->close(); + m_dqueStreamRespon[pSpdyStream->getPriority()].remove( pSpdyStream ); + if ( pSpdyStream->getHandler() ) + pSpdyStream->getHandler()->recycle(); + + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] recycleStream(), ID: %d, stream map size: %d " + , getLogId(), pSpdyStream->getStreamID(), m_mapStream.size() ) ); + } + //SpdyStreamPool::recycle( pSpdyStream ); + delete pSpdyStream; +} + + +int SpdyConnection::appendCtrlFrameHeader( SpdyFrameType type, uint8_t len ) +{ + static unsigned char s_achFrameHeader[8] = + { 0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08 }; + s_achFrameHeader[1] = m_bVersion; + s_achFrameHeader[3] = type; + s_achFrameHeader[7] = len; + + getBuf()->append( (char*)s_achFrameHeader, 8 ); + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] send %s, len: %d" + , getLogId(), getFrameName( type ), len ) ); + } + + return 0; +} + + +int SpdyConnection::sendFrame8Bytes( SpdyFrameType type, uint32_t uiVal1, uint32_t uiVal2 ) +{ + getBuf()->guarantee( 16 ); + appendCtrlFrameHeader( type, 8 ); + appendNbo4Bytes( getBuf(), uiVal1 ); + appendNbo4Bytes( getBuf(), uiVal2 ); + flush(); + return 0; +} + +int SpdyConnection::sendFrame4Bytes( SpdyFrameType type, uint32_t uiVal1 ) +{ + getBuf()->guarantee( 12 ); + appendCtrlFrameHeader( type, 4 ); + appendNbo4Bytes( getBuf(), uiVal1 ); + flush(); + return 0; +} + +int SpdyConnection::sendPing() +{ //Server initiate a Ping + m_uiLastPingID = m_uiServerStreamID; + m_uiServerStreamID += 2; + gettimeofday( &m_timevalPing, NULL ); + return appendPing( m_uiServerStreamID ); +} + +int SpdyConnection::sendSingleSettings(uint32_t uiID, uint32_t uiValue, uint8_t flags) +{ + static char clength[4] = { 0x00, 0x00, 0x00, 0x01 }; + getBuf()->guarantee( 12 ); + appendCtrlFrameHeader( SPDY_FRAME_SETTINGS, 12 ); + append4Bytes( getBuf(), clength ); + if(m_bVersion == 3) + uiID = htonl( uiID ) | ((uint32_t)flags); + else + uiID |= ((uint32_t)flags) << 24; + append4Bytes( getBuf(), (char *)&uiID ); + appendNbo4Bytes( getBuf(), uiValue ); + flush(); + return 0; +} + +int SpdyConnection::sendSettings(uint32_t uiMaxStreamNum, uint32_t uiWindowSize) +{ + static char cMaxStreamNumV2[8] = { 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x00 }; + static char cMaxStreamNumV3[8] = { 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x04 }; + static char cWindowSizeV3[4] = { 0x00, 0x00, 0x00, 0x07 }; + + getBuf()->guarantee( 28 ); + if(m_bVersion == 3) + { + appendCtrlFrameHeader( SPDY_FRAME_SETTINGS, 20 ); + getBuf()->append(cMaxStreamNumV3, 8 ); + appendNbo4Bytes( getBuf(), uiMaxStreamNum ); + append4Bytes( getBuf(), cWindowSizeV3 ); + appendNbo4Bytes( getBuf(), uiWindowSize ); + } + else + { + appendCtrlFrameHeader( SPDY_FRAME_SETTINGS, 12 ); + getBuf()->append(cMaxStreamNumV2, 8 ); + appendNbo4Bytes( getBuf(), uiMaxStreamNum ); + } + flush(); + return 0; +} + +int SpdyConnection::processPingFrame( SpdyFrameHeader * pHeader ) +{ + struct timeval CurTime; + long msec; + uint32_t id = pHeader->getHboData( 0 ); + if (( id & 1 ) == 1 ) + { + return appendPing( id ); + } + if ( id != m_uiLastPingID ) + { + //log , mismatch ping ID. + return 0; + } + + gettimeofday( &CurTime, NULL ); + msec = ( CurTime.tv_sec - m_timevalPing.tv_sec ) * 1000; + msec += ( CurTime.tv_usec - m_timevalPing.tv_usec ) / 1000; + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] Received Ping, ID=%d, Round trip " + "times=%d milli-seconds", getLogId(), m_uiLastPingID, msec ) ); + } + return 0; +} + +int SpdyConnection::append400BadReqReply( uint32_t uiStreamID ) +{ + return 0; +} + +SpdyStream* SpdyConnection::findStream( uint32_t uiStreamID ) +{ + StreamobjpMap::iterator it = m_mapStream.find(( void* ) uiStreamID ); + if ( it == m_mapStream.end() ) + return NULL; + return it.second(); +} + +int SpdyConnection::flush() +{ + BufferedOS::flush(); + if ( !isEmpty() ) + getStream()->continueWrite(); + getStream()->flush(); + return 0; +} + +int SpdyConnection::onCloseEx() +{ + if ( getStream()->isReadyToRelease() ) + return 0; + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] SpdyConnection::onCloseEx() ", getLogId() ) ); + } + getStream()->setState( HIOS_CLOSING ); + releaseAllStream(); + return 0; +}; + +int SpdyConnection::onTimerEx() +{ + int result = 0; + if ( m_flag & SPDY_CNN_FLAG_GOAWAY ) + result = releaseAllStream(); + else + result = timerRoutine(); + return result; +} + + +int SpdyConnection::processGoAwayFrame( SpdyFrameHeader * pHeader ) +{ + m_flag |= ( short )SPDY_CNN_FLAG_GOAWAY; + + onCloseEx(); + return true; +} + +int SpdyConnection::doGoAway(SpdyGoAwayStatus status) +{ + if ( D_ENABLED( DL_LESS ) ) + { + LOG_D(( getLogger(), "[%s] SpdyConnection::doGoAway(), status = %d ", getLogId(), status ) ); + } + sendGoAwayFrame( status ); + releaseAllStream(); + getStream()->setState( HIOS_CLOSING ); + getStream()->continueWrite(); + return 0; +} + + +int SpdyConnection::sendGoAwayFrame(SpdyGoAwayStatus status ) +{ + if ( m_bVersion == 3 ) + sendFrame8Bytes( SPDY_FRAME_GOAWAY, m_uiLastStreamID, status ); + else + sendFrame4Bytes( SPDY_FRAME_GOAWAY, m_uiLastStreamID ); + return 0; +} + + +int SpdyConnection::releaseAllStream() +{ + StreamobjpMap::iterator itn, it = m_mapStream.begin(); + for ( ; it != m_mapStream.end(); ) + { + itn = m_mapStream.next( it ); + recycleStream( it ); + it = itn; + } + getStream()->handlerReadyToRelease(); + return 0; +} + +int SpdyConnection::timerRoutine() +{ + StreamobjpMap::iterator itn, it = m_mapStream.begin(); + for ( ; it != m_mapStream.end(); ) + { + itn = m_mapStream.next( it ); + it.second()->onTimer(); + if ( it.second()->getState() == HIOS_DISCONNECTED ) + { + recycleStream( it ); + } + it = itn; + } + if ( m_mapStream.size() == 0 ) + { + if ( m_tmIdleBegin == 0 ) + m_tmIdleBegin = time( NULL ); + else if ( time( NULL ) - m_tmIdleBegin > 60 ) + doGoAway( SPDY_GOAWAY_OK ); + } + else + m_tmIdleBegin = 0; + return 0; +} + +void SpdyConnection::logDeflateInflateError( int n, int iDeflate ) +{ + static const char* cErroMsg[2] = { "Inflate Error, Error code =", "Deflate Error, Error code =" }; + LOG_INFO(( getLogger(), "[%s] Protocol Error, %s %d, go away!" + , getLogId(), cErroMsg[iDeflate], n ) ); +} + +int SpdyConnection::sendRespHeaders( IOVec &vector, int iheaderCount, uint32_t uiStreamID ) +{ + //Defalte the data and then add to m_pOutputBuff + int n = 0, total = 0; + uint32_t temp32; + char* pData = (char*)&temp32; + IOVec::iterator it; + int headerOffset = getBuf()->size(); + + getBuf()->guarantee( 28 ); + appendCtrlFrameHeader( SPDY_FRAME_SYN_REPLY, 0 ); + appendNbo4Bytes( getBuf(), uiStreamID ); + + total = 4; + if ( m_bVersion == 2 ) + { + *((uint16_t*)pData) = 0; + getBuf()->append(pData, 2); + total = 6; + *((uint16_t*)pData) = htons(( uint16_t )iheaderCount ); + } + else + *((uint32_t*)pData) = htonl(( uint32_t )iheaderCount ); + + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] sendRespHeaders(), ID: %d, headerCount: %d" + , getLogId(), uiStreamID, iheaderCount ) ); + } + n = m_deflator.spdyHeaderDeflate(pData, 8-total, getBuf() ,0 ); + if( n < 0 ) + { + logDeflateInflateError( n, 1); + return -1; + } + total += n; + + it = vector.begin(); + for ( ; it != vector.end(); it++ ) + { + if( ( it->iov_len == 0)&&(it->iov_base == NULL) ) + continue; + n = m_deflator.spdyHeaderDeflate(( char* )( it->iov_base ), + it->iov_len, getBuf(), ( it + 1 == vector.end() )? Z_SYNC_FLUSH : 0); + //assert( n >= 0 ); + if( n < 0 ) + { + logDeflateInflateError( n, 1); + return -1; + } + total += n; + } + temp32 = htonl( total ); + getBuf()->update(( headerOffset + 4 ), (char*)&temp32, 4 ); //Length + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] Append_Respons_Header() successfull, " + "StreamID=%lu, total=%d\n", getLogId(), uiStreamID, total ) ); + } + return total; +} +void SpdyConnection::move2ReponQue( SpdyStream* pSpdyStream ) +{ + m_dqueStreamRespon[pSpdyStream->getPriority()].append( pSpdyStream ); +} +int SpdyConnection::onWriteEx() +{ + SpdyStream* pSpdyStream = NULL; + int wantWrite = 0; + + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] onWriteEx() state: %d, output buffer size=%d\n ", + getLogId(), m_state, getBuf()->size() ) ); + } + flush(); + if ( !isEmpty() ) + return 0; + if ( getStream()->canWrite() & HIO_FLAG_BUFF_FULL ) + return 0; + + + for ( int i = 0; i < SPDY_STREAM_PRIORITYS; ++i ) + { + if ( m_dqueStreamRespon[i].empty() ) + continue; + DLinkedObj* it = m_dqueStreamRespon[i].begin();//SpdyStream* + DLinkedObj* itn; + for ( ; it != m_dqueStreamRespon[i].end(); ) + { + pSpdyStream = ( SpdyStream* )it; + itn = it->next(); + if ( pSpdyStream->isWantWrite() ) + { + pSpdyStream->onWrite(); + if ( pSpdyStream->isWantWrite() && ( pSpdyStream->getWindowOut() > 0 ) ) + ++wantWrite; + } + if ( pSpdyStream->getState() == HIOS_DISCONNECTED ) + { + recycleStream( pSpdyStream->getStreamID() ); + } + it = itn; + } + if ( getStream()->canWrite() & HIO_FLAG_BUFF_FULL ) + return 0; + } + if ( wantWrite == 0 ) + getStream()->suspendWrite(); + return 0; +} + + +void SpdyConnection::recycle() +{ + if ( D_ENABLED( DL_MORE ) ) + { + LOG_D(( getLogger(), "[%s] SpdyConnection::recycle()", + getLogId() )); + } + delete this; +} + +void SpdyConnection::resetStream( SpdyStream * pStream, SpdyRstErrorCode code ) +{ + sendRstFrame( pStream->getStreamID(), code ); + recycleStream( pStream->getStreamID() ); + +} + +void SpdyConnection::resetStream( StreamobjpMap::iterator it, SpdyRstErrorCode code ) +{ + sendRstFrame( it.second()->getStreamID(), code ); + recycleStream( it ); +} + diff --git a/src/spdy/spdyconnection.h b/src/spdy/spdyconnection.h new file mode 100644 index 000000000..dceee7d90 --- /dev/null +++ b/src/spdy/spdyconnection.h @@ -0,0 +1,185 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYCONNECTION_H +#define SPDYCONNECTION_H +#include "spdyzlibfilter.h" +#include "spdyprotocol.h" +#include +#include "util/autobuf.h" +#include +#include +#include "http/hiostream.h" +#include + + +#define SPDY_CNN_FLAG_GOAWAY (1<<0) + +#define SPDY_STREAM_PRIORITYS 8 + +typedef struct +{ + char* pName; + char* pValue; + uint16_t nameLen; + uint16_t ValueLen; +} NameValuePair; + +class SpdyStream; + +class SpdyConnection: public HioStreamHandler, public BufferedOS +{ +public: + SpdyConnection(); + virtual ~SpdyConnection(); + int onReadEx(); + int onReadEx2(); + int onWriteEx(); + + int isOutBufFull() const + { return getBuf()->size() >= SPDY_MAX_DATAFRAM_SIZE; } + + int flush(); + + int onCloseEx(); + + void recycle(); + + //Following functions are just placeholder + + //Placeholder + int init( HiosProtocol ver ); + int onInitConnected(); + + int onTimerEx(); + void move2ReponQue(SpdyStream* pSpdyStream); + int timerRoutine(); + + LOG4CXX_NS::Logger* getLogger() const + { + return getStream()->getLogger(); + } + + const char * getLogId() + { + return getStream()->getLogId(); + } + void continueWrite() + { getStream()->continueWrite(); } + + int32_t getServerInitWindowSize() const + { return m_iServerInitWindowSize; } + + int32_t getClientInitWindowSize() const + { return m_iClientInitWindowSize; } + + int appendPing(uint32_t uiStreamID) + { return sendFrame4Bytes( SPDY_FRAME_PING, uiStreamID ); } + + int sendRespHeaders(IOVec &vector, int iheaderCount, uint32_t uiStreamID); + + int sendWindowUpdateFrame( uint32_t id, int32_t delta ) + { return sendFrame8Bytes( SPDY_FRAME_WINDOW_UPDATE, + id, delta ); } + + int sendRstFrame( uint32_t uiStreamID, SpdyRstErrorCode code ) + { + return sendFrame8Bytes( SPDY_FRAME_RST_STREAM, uiStreamID, code ); + } + void recycleStream( uint32_t uiStreamID ); + static void replaceZero( char* pValue, int ilength ); + +private: + typedef THash< SpdyStream* > StreamobjpMap; + + SpdyStream* findStream(uint32_t uiStreamID); + int releaseAllStream(); + + int processControlFrame( SpdyFrameHeader* pHeader); + void printLogMsg( SpdyFrameHeader* pHeader); + + int checkReqline( char* pName, int ilength, uint8_t& flags); + + int processDataFrame( SpdyFrameHeader* pHeader); + int parseHeaders(char* pHeader, int ilength, int &NVPairCnt ); + SpdyStream* getNewStream(uint32_t uiStreamID, + int iPriority, uint8_t ubSpdy_Flags); + + int processSettingFrame( SpdyFrameHeader * pHeader ); + int processSynStreamFrame( SpdyFrameHeader* pHeader ); + int processHeaderFrame( SpdyFrameHeader* pHeader ); + int processPingFrame( SpdyFrameHeader * pHeader ); + int processGoAwayFrame( SpdyFrameHeader * pHeader ); + int processRstFrame( SpdyFrameHeader* pHeader ); + int processWindowUpdateFrame( SpdyFrameHeader* pHeader ); + + int sendPing(); + int sendSingleSettings(uint32_t uiID, uint32_t uiValue, uint8_t flags); + int sendSettings(uint32_t uiMaxStreamNum, uint32_t uiWindowSize); + int sendGoAwayFrame(SpdyGoAwayStatus status); + int doGoAway(SpdyGoAwayStatus status); + int append400BadReqReply(uint32_t uiStreamID); + void resetStream( SpdyStream * pStream, SpdyRstErrorCode code ); + void resetStream( StreamobjpMap::iterator it, SpdyRstErrorCode code ); + + int appendCtrlFrameHeader(SpdyFrameType type, uint8_t len ); + int sendFrame8Bytes( SpdyFrameType type, uint32_t uiVal1, uint32_t uiVal2 ); + int sendFrame4Bytes( SpdyFrameType type, uint32_t uiVal1 ); + + void recycleStream( StreamobjpMap::iterator it ); + int isSpdy3() const { return (m_bVersion == 3); } + void logDeflateInflateError( int n, int iDeflate ); + int appendReqHeaders(SpdyStream* arg1, int arg2); + int extractCompressedData(); + void skipRemainData(); + + +private: + LoopBuf m_bufInput; + AutoBuf m_bufInflate; + SpdyZlibFilter m_deflator; + SpdyZlibFilter m_inflator; + uint32_t m_uiServerStreamID; + uint32_t m_uiLastPingID; + uint32_t m_uiLastStreamID; + uint32_t m_uiGoAwayId; + int32_t m_iCurrentFrameRemain; + struct timeval m_timevalPing; + NameValuePair m_NameValuePairList[100]; + NameValuePair m_NameValuePairListReqline[3]; + DLinkQueue m_dqueStreamRespon[SPDY_STREAM_PRIORITYS]; + StreamobjpMap m_mapStream; + short m_state; + short m_flag; + char m_bVersion; + + int32_t m_iServerInitWindowSize; + int32_t m_iServerMaxStreams; + int32_t m_iClientInitWindowSize; + int32_t m_iClientMaxStreams; + int32_t m_tmIdleBegin; + int32_t m_SpdyHeaderMem[10]; + SpdyFrameHeader* m_pcurrentSpdyHeader; + + +private: + SpdyConnection(const SpdyConnection& other); + virtual SpdyConnection& operator=(const SpdyConnection& other); + +}; + +#endif // SPDYCONNECTION_H diff --git a/src/spdy/spdydebug.cpp b/src/spdy/spdydebug.cpp new file mode 100644 index 000000000..701f4c62e --- /dev/null +++ b/src/spdy/spdydebug.cpp @@ -0,0 +1,139 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include +#include +#include +#include +#include "spdydebug.h" + +int printheader( unsigned char* buff, int length ) +{ + static char namebuff[1000]; + static char strbuff[1000]; + uint16_t temp16, NameCount, theLength, curP = 0;; + + if ( length < 2 ) + return -1; + + memcpy( &temp16, buff + curP, 2 ); + curP += 2; + + NameCount = htons( temp16 ); + if ( NameCount == 0 ) + return NameCount; + + //NameCount = 20; + if ( curP + 2 > length ) + return -1; + + printf( "There are %d names in the pack\n", NameCount ); + + for ( int i = 0; i < NameCount; i++ ) + { + memcpy( &temp16, buff + curP, 2 ); + theLength = htons( temp16 ); + curP += 2; + + if ( curP + theLength > length ) + return -1; + + memcpy( namebuff, buff + curP, theLength ); + namebuff[theLength] = 0; + curP += theLength; + + if ( curP + 2 > length ) + return -1; + + memcpy( &temp16, buff + curP, 2 ); + theLength = htons( temp16 ); + curP += 2; + + if ( curP + theLength > length ) + return -1; + + memcpy( strbuff, buff + curP, theLength ); + strbuff[theLength] = 0; + printf( "%s %s\n", namebuff, strbuff ); + curP += theLength; + + if ( i + 1 == NameCount ) + { + printf( "End of buff, curP:length = %d:%d\n", curP, length ); + return 1; + } + + if ( curP + 2 > length ) + return -1; + } + + return 1; +} + +void printbuffstr( char* buff, int length ) +{ + static char pbuff[1000]; + + if ( length > 999 ) + length = 999; + + memcpy( pbuff, buff, length ); + pbuff[length] = 0; + printf( pbuff ); +} + +void printbuff( unsigned char* buff, int length ) +{ + static std::string tempstr; + static char pbuff[1000]; + tempstr.clear(); + + for ( int i = 0; i < length; ) + { + pbuff[0] = 0; + int ii = length - i; + + if ( ii < 16 ) + { + pbuff[0] = 0; + sprintf( pbuff, "%04X, ", i ); + tempstr += pbuff; + + for ( int ix = 0; ix < ii; ix++ ) + { + pbuff[0] = 0; + sprintf( pbuff, "%02X,", buff[i + ix] ); + tempstr += pbuff; + } + + tempstr += "\n"; + + break; + } + else + { + pbuff[0] = 0; + sprintf( pbuff, "%04X, %02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,\n", i, + buff[i], buff[i + 1], buff[i + 2], buff[i + 3], buff[i + 4], buff[i + 5], buff[i + 6], buff[i + 7], + buff[i + 8], buff[i + 9], buff[i +10], buff[i + 11], buff[i + 12], buff[i + 13], buff[i + 14], buff[i + 15] ); + tempstr += pbuff; + i += 16; + } + } + + printf( tempstr.c_str() ); +} diff --git a/src/spdy/spdydebug.h b/src/spdy/spdydebug.h new file mode 100644 index 000000000..79db78300 --- /dev/null +++ b/src/spdy/spdydebug.h @@ -0,0 +1,23 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYDEBUG_H +#define SPDYDEBUG_H +void printbuff( unsigned char* buff, int length); +int printheader( unsigned char* buff, int length); +void printbuffstr( char* buff, int length); +#endif // SPDYDEBUG_H \ No newline at end of file diff --git a/src/spdy/spdyprotocol.cpp b/src/spdy/spdyprotocol.cpp new file mode 100644 index 000000000..7e5f285bc --- /dev/null +++ b/src/spdy/spdyprotocol.cpp @@ -0,0 +1,36 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "spdyprotocol.h" +const char* getFrameName(unsigned char bframeType) +{ + static const char* pbyt[] = { "DATA", + "SYN_STREAM", + "SYN_REPLY", + "RST_STREAM", + "SETTINGS", + "NOOP", + "PING", + "GOAWAY", + "HEADERS", + "WINDOW_UPDATE", + "RCREDENTIAL"}; + if ( bframeType <= SPDY_FRAME_LAST_CONTROL_TYPE ) + return pbyt[bframeType]; + return "UNKONWN"; +} + diff --git a/src/spdy/spdyprotocol.h b/src/spdy/spdyprotocol.h new file mode 100644 index 000000000..1537d8f76 --- /dev/null +++ b/src/spdy/spdyprotocol.h @@ -0,0 +1,239 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYPROTOCOL_H +#define SPDYPROTOCOL_H +#include +//#include +#include +// Types of SPDY frames. + +enum SpdyFrameType +{ + SPDY_FRAME_DATA = 0, + SPDY_FRAME_SYN_STREAM = 1, + SPDY_FRAME_FIRST_CONTROL_TYPE = SPDY_FRAME_SYN_STREAM, + SPDY_FRAME_SYN_REPLY, + SPDY_FRAME_RST_STREAM, + SPDY_FRAME_SETTINGS, + SPDY_FRAME_NOOP, // Because it is valid in SPDY/2, kept for identifiability/enum order. + SPDY_FRAME_PING, + SPDY_FRAME_GOAWAY, + SPDY_FRAME_HEADERS, + SPDY_FRAME_WINDOW_UPDATE, + SPDY_FRAME_CREDENTIAL, + SPDY_FRAME_LAST_CONTROL_TYPE = SPDY_FRAME_CREDENTIAL +}; +// Flags on data packets. +enum SpdyDataFlags +{ + SPDY_DATA_FLAG_NONE = 0, + SPDY_DATA_FLAG_FIN = 1, +}; + +// Flags on control packets +enum SpdyControlFlags +{ + SPDY_CTRL_FLAG_NONE = 0, + SPDY_CTRL_FLAG_FIN = 1, + SPDY_CTRL_FLAG_UNIDIRECTIONAL = 2 +}; + +// Flags on the SETTINGS control frame. +enum SpdySettingsControlFlags +{ + SPDY_SETTINGS_FLAG_CLEAR_PREVIOUS = 0x1 +}; + +// Flags for settings within a SETTINGS frame. +enum SpdySettingsFlags +{ + SPDY_SETTINGS_FLAG_NONE = 0x0, + SPDY_SETTINGS_FLAG_PLEASE_PERSIST = 0x1, + SPDY_SETTINGS_FLAG_PERSISTED = 0x2 +}; + +// List of known settings. +enum SpdySettingsIds +{ + SPDY_SETTINGS_UPLOAD_BANDWIDTH = 0x1, + SPDY_SETTINGS_DOWNLOAD_BANDWIDTH = 0x2, + // Network round trip time in milliseconds. + SPDY_SETTINGS_ROUND_TRIP_TIME = 0x3, + SPDY_SETTINGS_MAX_CONCURRENT_STREAMS = 0x4, + // TCP congestion window in packets. + SPDY_SETTINGS_CURRENT_CWND = 0x5, + // Downstream byte retransmission rate in percentage. + SPDY_SETTINGS_DOWNLOAD_RETRANS_RATE = 0x6, + // Initial window size in bytes + SPDY_SETTINGS_INITIAL_WINDOW_SIZE = 0x7 +}; + +// Status codes for RST_STREAM frames. +enum SpdyRstErrorCode +{ + SPDY_RST_STREAM_INVALID = 0, + SPDY_RST_STREAM_PROTOCOL_ERROR = 1, + SPDY_RST_STREAM_INVALID_STREAM = 2, + SPDY_RST_STREAM_REFUSED_STREAM = 3, + SPDY_RST_STREAM_UNSUPPORTED_VERSION = 4, + SPDY_RST_STREAM_CANCEL = 5, + SPDY_RST_STREAM_INTERNAL_ERROR = 6, + SPDY_RST_STREAM_FLOW_CONTROL_ERROR = 7, + SPDY_RST_STREAM_IN_USE = 8, + SPDY_RST_STREAM_ALREADY_CLOSED = 9, + SPDY_RST_STREAM_INVALID_CREDENTIALS = 10, + SPDY_RST_STREAM_FRAME_TOO_LARGE = 11, + SPDY_RST_STREAM_NUM_STATUS_CODES = 12 +}; + +// Status codes for GOAWAY frames. +enum SpdyGoAwayStatus +{ + SPDY_GOAWAY_INVALID = -1, + SPDY_GOAWAY_OK = 0, + SPDY_GOAWAY_PROTOCOL_ERROR = 1, + SPDY_GOAWAY_INTERNAL_ERROR = 2, + SPDY_GOAWAY_NUM_STATUS_CODES = 3 +}; + +class SpdyFrameHeader +{ + struct spdy_ctl_hdr + { + unsigned char m_b80; + unsigned char m_bVer; + unsigned char m_bType0; + unsigned char m_bType; + }; + + union + { + struct spdy_ctl_hdr m_ctl; + uint32_t m_iStreamId; + + } m_un; + unsigned char m_bFlags; + unsigned char m_bLength[3]; + uint32_t m_data[]; +public: + SpdyFrameHeader() {} + ~SpdyFrameHeader() {} + + int isControlFrame() const { return m_un.m_ctl.m_b80 == 0x80; } + unsigned char getType() const { return (m_un.m_ctl.m_b80 == 0x80)? (m_un.m_ctl.m_bType):( 0 ); } + unsigned char getFlags() const { return m_bFlags; } + unsigned char getVersion() const{ return m_un.m_ctl.m_bVer; } + + uint32_t getDataStreamId() const{ return ntohl( m_un.m_iStreamId); } + void setStreamId( uint32_t id ) { m_un.m_iStreamId = htonl( id ); } + + + uint32_t getLength() const + { return ( ((uint32_t)m_bLength[0]) << 16 ) | + ( ((uint32_t)m_bLength[1]) << 8 ) | + ( m_bLength[2] ); + } + void setLength( uint32_t l ) + { + m_bLength[ 0 ] = ( l >> 16 ) & 0xff; + m_bLength[ 1 ] = ( l >> 8 ) & 0xff; + m_bLength[ 2 ] = l & 0xff; + } + uint32_t getData( int n ) const { return m_data[n]; } + uint32_t getHboData( int n ) const { return ntohl( m_data[n] ); } +}; + +inline uint16_t beReadUint16( const unsigned char * p ) +{ + return ( (uint16_t)(*p) ) << 8 | *( p + 1 ); +} + +inline uint32_t beReadUint32( const unsigned char * p ) +{ + register uint32_t v = *p++; + v = ( v << 8 ) | *p++; + v = ( v << 8 ) | *p++; + v = ( v << 8 ) | *p; + return v ; +} + +inline uint16_t beReadUint16Adv( unsigned char * &p ) +{ + register uint16_t v = *p++; + v = ( v << 8 ) | *p++; + return v; +} + +inline uint32_t beReadUint32Adv( unsigned char * &p ) +{ + register uint32_t v = *p++; + v = ( v << 8 ) | *p++; + v = ( v << 8 ) | *p++; + v = ( v << 8 ) | *p++; + return v ; +} + +inline unsigned char * beWriteUint16( unsigned char * p, uint16_t v ) +{ + *p++ = v >> 8; + *p++ = v & 0xff; + return p; +} + +inline unsigned char * beWriteUint32( unsigned char * p, uint32_t v ) +{ + *p++ = v >> 24; + *p++ = ( v >> 16 ) & 0xff; + *p++ = ( v >> 8 ) & 0xff; + *p++ = v & 0xff; + return p; + +} + +const char* getFrameName(unsigned char bframeType); + +class SpdySettingPairs +{ + union + { + unsigned char m_b[4]; + uint32_t m_uiTemp; + + } m_un1; + uint32_t m_uiValue; + +public: + void swapID() + { + unsigned char ch; + ch = m_un1.m_b[0]; + m_un1.m_b[0] = m_un1.m_b[3]; + m_un1.m_b[3] = ch; + ch = m_un1.m_b[1]; + m_un1.m_b[1] = m_un1.m_b[2]; + m_un1.m_b[2] = ch; + } + unsigned char getFlags() const { return m_un1.m_b[0]; } + uint32_t getValue() const { return htonl(m_uiValue); } + uint32_t getID() const { return ( htonl(m_un1.m_uiTemp) & 0xFFFFFF); } +}; + +#define SPDY_MAX_DATAFRAM_SIZE 65536 + + +#endif // SPDYPROTOCOL_H diff --git a/src/spdy/spdystream.cpp b/src/spdy/spdystream.cpp new file mode 100644 index 000000000..7ce8b6232 --- /dev/null +++ b/src/spdy/spdystream.cpp @@ -0,0 +1,318 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#include "spdystream.h" + +#include "spdyconnection.h" + +#include +#include +#include + + + +SpdyStream::SpdyStream() + :m_uiStreamID(0) + ,m_iPriority(0) + ,m_pSpdyCnn(NULL) +{ +} + + +const char * SpdyStream::buildLogId() +{ + int len ; + AutoStr2 & id = getIdBuf(); + + len = safe_snprintf( id.buf(), MAX_LOGID_LEN, "%s-%d", + m_pSpdyCnn->getStream()->getLogId(), m_uiStreamID ); + id.setLen( len ); + return id.c_str(); +} + + +int SpdyStream::init(uint32_t StreamID, + int Priority, SpdyConnection* pSpdyCnn, uint8_t flags, HioStreamHandler * pHandler ) +{ + HioStream::reset(); + pHandler->assignStream( this ); + setLogIdBuild( 0 ); + + setState(HIOS_CONNECTED); + setFlag( (flags & ( SPDY_CTRL_FLAG_FIN | SPDY_CTRL_FLAG_UNIDIRECTIONAL)), 1 ); + + m_bufIn.clear(); + m_uiStreamID = StreamID; + m_iBytesAllowSend = SPDY_MAX_DATAFRAM_SIZE; + m_iWindowOut = pSpdyCnn->getClientInitWindowSize(); + m_iWindowIn = pSpdyCnn->getServerInitWindowSize(); + m_iPriority = Priority; + m_pSpdyCnn = pSpdyCnn; + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::init(), id: %d. ", + getLogId(), StreamID )); + } + return 0; +} +int SpdyStream::onInitConnected() +{ + getHandler()->onInitConnected(); + if ( isWantRead() ) + getHandler()->onReadEx(); + if ( isWantWrite() ) + getHandler()->onWriteEx(); + return 0; +} + +SpdyStream::~SpdyStream() +{ + m_bufIn.clear(); +} + +int SpdyStream::appendReqData(char* pData, int len, uint8_t flags) +{ + if (m_bufIn.append(pData, len)==-1) + return -1; + if ( isFlowCtrl() ) + m_iWindowIn -= len; + //Note: SPDY_CTRL_FLAG_FIN is directly mapped to HIO_FLAG_PEER_SHUTDOWN + // SPDY_CTRL_FLAG_UNIDIRECTIONAL is directly mapped to HIO_FLAG_LOCAL_SHUTDOWN + if ( flags & ( SPDY_CTRL_FLAG_FIN | SPDY_CTRL_FLAG_UNIDIRECTIONAL) ) + setFlag( flags & ( SPDY_CTRL_FLAG_FIN | SPDY_CTRL_FLAG_UNIDIRECTIONAL), 1 ); + + if (isWantRead()) + getHandler()->onReadEx(); + return len; +} +//***int SpdyStream::read( char * buf, int len )***// +// return > 0: number of bytes of that has been read +// return = 0: 0 byte of data has been read, but there will be more data coming, +// need to read again +// return = -1: EOF (End of File) There is no more data need to be read, the +// stream can be removed +int SpdyStream::read( char * buf, int len ) +{ + int ReadCount; + if ( getState()==HIOS_DISCONNECTED ) + return -1; + + ReadCount = m_bufIn.moveTo( buf, len ); + if ( ReadCount == 0) + { + if ( getFlag( HIO_FLAG_PEER_SHUTDOWN ) ) + { + return -1; //EOF (End of File) There is no more data need to be read + } + } + return ReadCount; +} + +void SpdyStream::continueRead() +{ + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::continueRead()", + getLogId() )); + } + setFlag(HIO_FLAG_WANT_READ, 1); + if ( m_bufIn.size() > 0) + getHandler()->onReadEx(); +} +void SpdyStream:: continueWrite() +{ + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::continueWrite()", + getLogId() )); + } + setFlag(HIO_FLAG_WANT_WRITE, 1); + m_pSpdyCnn->continueWrite(); + +} +void SpdyStream::onTimer() +{ + getHandler()->onTimerEx(); +} + +int SpdyStream::sendFin() +{ + char achHeader[8]; + + if ( getState() == HIOS_SHUTDOWN ) + return 0; + + setState(HIOS_SHUTDOWN); + + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::sendFin()", + getLogId() )); + } + buildDataFrameHeader( achHeader, 0 ); + m_pSpdyCnn->cacheWrite( achHeader, sizeof( achHeader ) ); + m_pSpdyCnn->flush(); + return 0; +} + +int SpdyStream::close() +{ + if (getState()!=HIOS_CONNECTED) + return 0; + if (getHandler()) + getHandler()->onCloseEx(); + sendFin(); + setFlag( HIO_FLAG_WANT_WRITE, 1 ); + setState(HIOS_DISCONNECTED); + m_pSpdyCnn->continueWrite(); + //if (getHandler()) + //{ + // getHandler()->recycle(); + // setHandler( NULL ); + //} + //m_pSpdyCnn->recycleStream( m_uiStreamID ); + return 0; +} + + +int SpdyStream::flush() +{ + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::flush()", + getLogId() )); + } + return 0; +} + +int SpdyStream::writev( IOVec &vector, int total ) +{ + int totalSended = 0; + IOVec::iterator it; + if ( getState()==HIOS_DISCONNECTED ) + return -1; + if (getFlag( HIO_FLAG_BUFF_FULL) ) + return 0; + + it = vector.begin(); + for (; it != vector.end(); it++) + { + totalSended += write( (char*)(it->iov_base), it->iov_len) ; + if (getFlag( HIO_FLAG_BUFF_FULL) ) + return totalSended; + } + return totalSended; +} + +int SpdyStream::write( const char * buf, int len ) +{ + IOVec iov; + int allowed; + if ( getState() == HIOS_DISCONNECTED ) + return -1; + if (( m_pSpdyCnn->isOutBufFull() )|| + ( 0 >= m_iBytesAllowSend )) + { + setFlag( HIO_FLAG_BUFF_FULL|HIO_FLAG_WANT_WRITE, 1 ); + m_pSpdyCnn->continueWrite(); + return 0; + } + + allowed = m_iBytesAllowSend; + if ( len < allowed ) + allowed = len; + + iov.append( buf, allowed ); + if ( sendData( &iov, allowed ) == -1 ) + { + return -1; + } + return allowed; +} + + +int SpdyStream::onWrite() +{ + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::onWrite()", + getLogId() )); + } + if ( m_pSpdyCnn->isOutBufFull() ) + return 0; + m_iBytesAllowSend = SPDY_MAX_DATAFRAM_SIZE; + if ( m_iBytesAllowSend > m_iWindowOut ) + m_iBytesAllowSend = m_iWindowOut; + if ( m_iBytesAllowSend <= 0 ) + return 0; + setFlag( HIO_FLAG_BUFF_FULL, 0 ); + + if ( isWantWrite() ) + getHandler()->onWriteEx(); + if ( isWantWrite() ) + m_pSpdyCnn->continueWrite(); + return 0; +} + +void SpdyStream::buildDataFrameHeader( char * pHeader, int length ) +{ + *(uint32_t *)pHeader = htonl( m_uiStreamID ); + *((uint32_t *)pHeader + 1 ) = htonl( length ); + if ( getState() >= HIOS_CLOSING ) + pHeader[4] = 1; + +} + +int SpdyStream::sendData( IOVec * pIov, int total ) +{ + char achHeader[8]; + int ret; + buildDataFrameHeader( achHeader, total ); + pIov->push_front( achHeader, 8 ); + ret = m_pSpdyCnn->cacheWritev( *pIov ); + if ( D_ENABLED( DL_LESS )) + { + LOG_D(( getLogger(), "[%s] SpdyStream::sendData(), total: %d, ret: %d", + getLogId(), total, ret )); + } + if ( ret == -1 ) + { + setFlag( HIO_FLAG_ABORT, 1 ); + return -1; + } + bytesSent( total ); + m_iBytesAllowSend -= total; + if ( isFlowCtrl() ) + m_iWindowOut -= total; + if ( m_iBytesAllowSend <= 0 ) + setFlag( HIO_FLAG_BUFF_FULL, 1 ); + return total; +} + + +int SpdyStream::sendHeaders( IOVec &vector, int headerCount ) +{ + if ( getState() == HIOS_DISCONNECTED ) + return -1; + m_pSpdyCnn->move2ReponQue(this); + return m_pSpdyCnn->sendRespHeaders(vector, headerCount, m_uiStreamID); +} + + + + diff --git a/src/spdy/spdystream.h b/src/spdy/spdystream.h new file mode 100644 index 000000000..0e96ea41b --- /dev/null +++ b/src/spdy/spdystream.h @@ -0,0 +1,128 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYSTREAM_H +#define SPDYSTREAM_H + +#include + +#include +#include + +#include + + +class SpdyConnection; + +class SpdyStream: public DLinkedObj, public HioStream +{ + +public: + SpdyStream(); + ~SpdyStream(); + + int init(uint32_t StreamID, + int Priority, SpdyConnection* pSpdyCnn, uint8_t Spdy_Flags, HioStreamHandler * pHandler ); + int onInitConnected(); + + int getPriority() const + { + return m_iPriority; + } + + int appendReqData(char* pData, int len, uint8_t Spdy_Flags); + + int read( char * buf, int len ); + + uint32_t getStreamID() + { return m_uiStreamID; } + + int write( const char * buf, int len ); + int writev( IOVec &vector, int total ); + + int sendfile( IOVec &vector, int &total, int fdSrc, off_t off, size_t size ) + { + return 0; + }; + void switchWriteToRead() {}; + + int flush(); + int sendHeaders( IOVec &vector, int headerCount ); + + void suspendRead() + { setFlag(HIO_FLAG_WANT_READ, 0); } + void suspendWrite() + { setFlag(HIO_FLAG_WANT_WRITE, 0); } + + void continueRead(); + void continueWrite(); + + void onTimer(); + int close(); + + int onWrite(); + + int isFlowCtrl() const { return getFlag( HIO_FLAG_FLOWCTRL ); } + + int32_t getWindowOut() const { return m_iWindowOut; } + void adjWindowOut( int32_t n ) { m_iWindowOut += n; } + + int32_t getWindowIn() const { return m_iWindowIn; } + void adjWindowIn( int32_t n ) { m_iWindowIn += n; } + + void clearBufIn() { m_bufIn.clear(); } + LoopBuf* getBufIn() { return &m_bufIn; } + int appendInputData( const char* pData, int len ) + { + return m_bufIn.append(pData, len); + } + + void appendInputData( char ch ) + { + return m_bufIn.append( ch ); + } + + +private: + SpdyStream(const SpdyStream& other); + SpdyStream& operator=(const SpdyStream& other); + bool operator==(const SpdyStream& other) const; + + void buildDataFrameHeader( char * pHeader, int length ); + int sendData( IOVec * pIov, int total ); + int sendFin(); + + + +protected: + virtual const char * buildLogId(); + +private: + uint32_t m_uiStreamID; + int m_iPriority; + int m_iBytesAllowSend; + int32_t m_iWindowOut; + int32_t m_iWindowIn; + SpdyConnection* m_pSpdyCnn; + LoopBuf m_bufIn; +}; + + + + + +#endif // SPDYSTREAM_H diff --git a/src/spdy/spdystreampool.cpp b/src/spdy/spdystreampool.cpp new file mode 100644 index 000000000..938f4f09d --- /dev/null +++ b/src/spdy/spdystreampool.cpp @@ -0,0 +1,44 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "spdystreampool.h" +#include "spdystream.h" + +Pool SpdyStreamPool::s_pool; +void SpdyStreamPool::recycle( SpdyStream* pStream ) +{ + s_pool.recycle( pStream ); +} + +SpdyStream* SpdyStreamPool::getSpdyStream() +{ + SpdyStream * p = s_pool.get(); + return p; +} + +void SpdyStreamPool::recycle( SpdyStream** pStream, int n ) +{ + s_pool.recycle( (void **)pStream, n ); +} + +int SpdyStreamPool::getSpdyStreams( SpdyStream** pStream, int n) +{ + int ret = s_pool.get( pStream, n); + return ret; +} + + diff --git a/src/spdy/spdystreampool.h b/src/spdy/spdystreampool.h new file mode 100644 index 000000000..091c073df --- /dev/null +++ b/src/spdy/spdystreampool.h @@ -0,0 +1,36 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYSTREAMPOOL_H +#define SPDYSTREAMPOOL_H +#include +#include +class SpdyStream; +typedef ObjPool Pool; +class SpdyStreamPool : public ObjPool +{ + static Pool s_pool; + SpdyStreamPool(); + ~SpdyStreamPool(); +public: + static void recycle( SpdyStream* pStream ); + static SpdyStream* getSpdyStream(); + static void recycle( SpdyStream** pStream, int n ); + static int getSpdyStreams( SpdyStream** pStream, int n ); +}; + +#endif // SPDYSTREAMPOOL_H diff --git a/src/spdy/spdyzlibfilter.cpp b/src/spdy/spdyzlibfilter.cpp new file mode 100644 index 000000000..f86966c8c --- /dev/null +++ b/src/spdy/spdyzlibfilter.cpp @@ -0,0 +1,366 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "spdyzlibfilter.h" + +// SPDY 2 dictionary. +// This is just a hacked dictionary to use for shrinking HTTP-like headers. +static const unsigned char s_spdyV2Dictionary[] = + "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" + "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" + "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" + "-agent10010120020120220320420520630030130230330430530630740040140240340440" + "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" + "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" + "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" + "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" + "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" + "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" + "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" + "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" + ".1statusversionurl"; +//const int kV2DictionarySize = arraysize(kV2Dictionary); + +// SPDY 3 dictionary. +static const unsigned char s_spdyV3Dictionary[] = +{ + 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // ....opti + 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // ons....h + 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // ead....p + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // ost....p + 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // ut....de + 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // lete.... + 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // trace... + 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // .accept. + 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep + 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t-charse + 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t....acc + 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ept-enco + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // ding.... + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // accept-l + 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // anguage. + 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep + 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t-ranges + 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // ....age. + 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // ...allow + 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // ....auth + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // orizatio + 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n....cac + 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // he-contr + 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // ol....co + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // nnection + 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // ....cont + 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // ent-base + 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // ....cont + 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ent-enco + 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // ding.... + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // content- + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // language + 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // ....cont + 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // ent-leng + 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // th....co + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // ntent-lo + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // cation.. + 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten + 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t-md5... + 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // .content + 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // -range.. + 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten + 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t-type.. + 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // ..date.. + 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // ..etag.. + 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // ..expect + 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // ....expi + 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // res....f + 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // rom....h + 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // ost....i + 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f-match. + 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // ...if-mo + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // dified-s + 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // ince.... + 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // if-none- + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // match... + 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // .if-rang + 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e....if- + 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // unmodifi + 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // ed-since + 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // ....last + 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // -modifie + 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d....loc + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // ation... + 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // .max-for + 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // wards... + 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // .pragma. + 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // ...proxy + 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // -authent + 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // icate... + 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // .proxy-a + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // uthoriza + 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // tion.... + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // range... + 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // .referer + 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // ....retr + 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y-after. + 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // ...serve + 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r....te. + 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // ...trail + 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // er....tr + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // ansfer-e + 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // ncoding. + 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // ...upgra + 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // de....us + 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // er-agent + 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // ....vary + 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // ....via. + 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // ...warni + 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // ng....ww + 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w-authen + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // ticate.. + 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // ..method + 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // ....get. + 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // ...statu + 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s....200 + 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // .OK....v + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // ersion.. + 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // ..HTTP.1 + 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // .1....ur + 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l....pub + 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // lic....s + 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // et-cooki + 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e....kee + 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p-alive. + 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // ...origi + 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n1001012 + 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 01202205 + 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 20630030 + 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 23033043 + 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 05306307 + 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 40240540 + 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 64074084 + 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 09410411 + 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 41241341 + 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 44154164 + 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 17502504 + 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 505203.N + 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // on-Autho + 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // ritative + 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // .Informa + 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // tion204. + 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // No.Conte + 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // nt301.Mo + 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // ved.Perm + 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // anently4 + 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 00.Bad.R + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // equest40 + 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1.Unauth + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // orized40 + 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3.Forbid + 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // den404.N + 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // ot.Found + 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 500.Inte + 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // rnal.Ser + 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // ver.Erro + 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r501.Not + 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // .Impleme + 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // nted503. + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // Service. + 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // Unavaila + 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // bleJan.F + 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // eb.Mar.A + 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // pr.May.J + 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // un.Jul.A + 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // ug.Sept. + 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // Oct.Nov. + 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // Dec.00.0 + 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0.00.Mon + 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // ..Tue..W + 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // ed..Thu. + 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // .Fri..Sa + 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t..Sun.. + 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // GMTchunk + 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // ed.text. + 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // html.ima + 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // ge.png.i + 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // mage.jpg + 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // .image.g + 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // if.appli + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x + 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // ml.appli + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x + 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // html.xml + 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // .text.pl + 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // ain.text + 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // .javascr + 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // ipt.publ + 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // icprivat + 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // emax-age + 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // .gzip.de + 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // flate.sd + 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // chcharse + 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t.utf-8c + 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // harset.i + 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // so-8859- + 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1.utf-.. + 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // .enq.0. +}; + +static const unsigned char * s_dicts[] = { NULL, s_spdyV2Dictionary, s_spdyV3Dictionary }; +static int s_dictsLen[] = + { 0, sizeof( s_spdyV2Dictionary ), sizeof( s_spdyV3Dictionary ) }; + +SpdyZlibFilter::SpdyZlibFilter() + : m_version( 2 ) + , m_isInflator( 0 ) +{ + memset( &m_stream, 0, sizeof( m_stream ) ); +} + +int SpdyZlibFilter::init( int isInflator, int verSpdy ) +{ + int ret; + + m_isInflator = isInflator; + assert( (uint)verSpdy < sizeof( s_dicts ) / sizeof( char * ) ); + m_version = verSpdy; + if ( isInflator ) + { + if ( m_stream.state ) + ret = inflateReset( &m_stream ); + else + ret = inflateInit2( &m_stream, 15 ); + } + else + { + if ( m_stream.state ) + ret = deflateReset( &m_stream ); + else + ret = deflateInit( &m_stream, -1 ); + + ret = deflateSetDictionary( &m_stream, s_dicts[ m_version ], + s_dictsLen[ m_version ] ); + } + + return ret; +} + +SpdyZlibFilter::~SpdyZlibFilter() +{ + release(); +} + +int SpdyZlibFilter::release() +{ + if ( m_isInflator ) + inflateEnd( &m_stream ); + else + deflateEnd( &m_stream ); + return 0; +} + +int SpdyZlibFilter::spdyHeaderInflate( char* pSource, uint32_t length, AutoBuf& bufInflate) +{ + int ret; + + m_stream.avail_in = length; + m_stream.next_in = ( unsigned char * )pSource; + m_stream.avail_out = bufInflate.available(); + m_stream.next_out = ( unsigned char* )bufInflate.end(); + + while( m_stream.avail_in ) + { + ret = inflate( &m_stream, Z_SYNC_FLUSH ); + if ( ret == Z_STREAM_ERROR ) + return -1; + + switch ( ret ) + { + + case Z_NEED_DICT: + /* Setting the dictionary for the SPDY zlib compression. */ + ret = inflateSetDictionary( &m_stream, s_dicts[ m_version ], + s_dictsLen[ m_version ] ); + + if ( ret != Z_OK ) + { + inflateEnd( &m_stream ); + return -1; + } + continue; + + case Z_DATA_ERROR: + return Z_DATA_ERROR; + + case Z_MEM_ERROR: + return Z_MEM_ERROR; + + case Z_OK: + break; + + default: + return ret; + } + bufInflate.used( m_stream.next_out - ( unsigned char* )bufInflate.end() ); + if(m_stream.avail_out == 0) + { + bufInflate.grow(512); + m_stream.avail_out = bufInflate.available(); + m_stream.next_out = ( unsigned char* )bufInflate.end(); + } + else + { + break; + } + } + return bufInflate.size(); +} + +int SpdyZlibFilter::spdyHeaderDeflate(char* pSource, uint32_t length, LoopBuf* ploopbuf, int flush) +{ + int ret; + int old_size = ploopbuf->size(); + ploopbuf->guarantee(1024); + + m_stream.avail_in = length; + m_stream.next_in = ( unsigned char * )pSource; + m_stream.avail_out = ploopbuf->contiguous(); + m_stream.next_out = ( unsigned char * )ploopbuf->end(); + while ( m_stream.avail_in ) + { + ret = deflate( &m_stream, flush ); + + if (( ret == Z_OK ) || ( ret == Z_STREAM_END ) ) + { + ploopbuf->used( (char *)m_stream.next_out - ploopbuf->end() ); + if( m_stream.avail_out == 0 ) + { + ploopbuf->guarantee(1024); + m_stream.avail_out = ploopbuf->contiguous(); + m_stream.next_out = ( unsigned char * )ploopbuf->end(); + } + else + break; + } + else + { + if( ( ret == Z_BUF_ERROR) && (m_stream.avail_out > 0) && (m_stream.avail_in == 0) ) + break; + return ret; + } + } + return ploopbuf->size() - old_size; +} + diff --git a/src/spdy/spdyzlibfilter.h b/src/spdy/spdyzlibfilter.h new file mode 100644 index 000000000..02ffe9436 --- /dev/null +++ b/src/spdy/spdyzlibfilter.h @@ -0,0 +1,60 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef SPDYZLIBFILTER_H +#define SPDYZLIBFILTER_H +#include +#include +#include +#include +#include +#include "spdyprotocol.h" +#include "zlib.h" +#include /* basic system data types */ +#include "util/autobuf.h" +#include "util/loopbuf.h" +#include "spdydebug.h" +/** + * Context for zlib deflating and inflating. + * Allows to use the same zlib stream on multiple frames. (Needed + * for inflating multiple compressed headers on a SPDY stream.) + */ + +class SpdyZlibFilter +{ + +private: + z_stream m_stream; + short m_version; + short m_isInflator; + +private: + SpdyZlibFilter(const SpdyZlibFilter& other); + SpdyZlibFilter& operator=(const SpdyZlibFilter& other); + bool operator==(const SpdyZlibFilter& other) const; + +public: + SpdyZlibFilter(); + ~SpdyZlibFilter(); + int init( int isInflator, int verSpdy ); + int release(); + int spdyHeaderInflate(char* pSource, uint32_t length, AutoBuf& bufInflate); + int spdyHeaderDeflate(char* pSource, uint32_t length, LoopBuf* ploopbuf, int flush); + +}; + +#endif // SPDYZLIBFILTER_H diff --git a/src/ssi/ssiengine.cpp b/src/ssi/ssiengine.cpp index 41fc96a4c..971b82b08 100644 --- a/src/ssi/ssiengine.cpp +++ b/src/ssi/ssiengine.cpp @@ -74,7 +74,7 @@ int SSIEngine::startExecute( HttpConnection * pConn, pRuntime->init(); pRuntime->initConfig( pReq->getSSIConfig() ); pReq->setSSIRuntime( pRuntime ); - pConn->getResp()->reset(); + pConn->getResp()->reset(RespHeader::REGULAR); //pConn->getResp()->prepareHeaders( pReq ); //pConn->setupChunkOS( 0 ); HttpCgiTool::processContentType( pReq, pConn->getResp(), @@ -281,7 +281,6 @@ int SSIEngine::processFileAttr( HttpConnection * pConn, SSIComponent * pComponen int SSIEngine::processSubReq( HttpConnection * pConn, SubstItem *pItem ) { - char achBuf1[8192]; char achBuf[40960]; char * p; int len; diff --git a/src/ssi/ssiscript.cpp b/src/ssi/ssiscript.cpp index a3b537e4d..4f7cf48a8 100644 --- a/src/ssi/ssiscript.cpp +++ b/src/ssi/ssiscript.cpp @@ -122,7 +122,6 @@ int Expression::appendRegex( const char * pBegin, int len, int flag ) int Expression::parse( const char * pBegin, const char * pEnd ) { - int type = ExprToken::EXP_STRING; char achBuf[ 10240]; char * p = achBuf; char quote = 0; @@ -540,7 +539,8 @@ int SSIScript::parseAttrs( int cmd, const char * pBegin, const char * pEnd ) attr = SSI_ENC_NONE; for( ; attr <= SSI_ENC_ENTITY; attr++ ) { - if ( strncasecmp( s_SSI_Attrs[attr], pValue, valLen ) == 0 ) + if (( strncasecmp( s_SSI_Attrs[attr], pValue, valLen ) == 0 ) + &&( s_SSI_Attrs_len[attr] == valLen )) { break; } @@ -703,7 +703,7 @@ int SSIScript::parse_ssi_directive( const char * pBegin, const char * pEnd ) if ( pBegin >= pEnd ) return 0; int cmd = 1; - for( ; cmd < sizeof( s_SSI_Cmd ) / sizeof( const char * ); cmd++ ) + for( ; cmd < (int)( sizeof( s_SSI_Cmd ) / sizeof( const char * )); cmd++ ) { if ( strncasecmp( s_SSI_Cmd[cmd], pBegin, s_SSI_Cmd_len[cmd] ) == 0 ) @@ -863,7 +863,6 @@ int SSIScript::processSSIFile( SSITagConfig * pConfig, int fd ) int SSIScript::parse( SSITagConfig * pConfig, const char * pScriptPath ) { - struct stat st; int fd; int ret; fd = nio_open( pScriptPath, O_RDONLY, 0644 ); diff --git a/src/sslpp/CMakeLists.txt b/src/sslpp/CMakeLists.txt index a0d422e86..6c6532a3a 100644 --- a/src/sslpp/CMakeLists.txt +++ b/src/sslpp/CMakeLists.txt @@ -9,6 +9,7 @@ SET(sslpp_STAT_SRCS sslerror.cpp sslconnection.cpp sslcontext.cpp + sslocspstapling.cpp ../http/requestvars.cpp ) diff --git a/src/sslpp/Makefile.am b/src/sslpp/Makefile.am index f9dcb83fe..65b35644b 100755 --- a/src/sslpp/Makefile.am +++ b/src/sslpp/Makefile.am @@ -5,6 +5,6 @@ INCLUDES = -I$(top_srcdir)/src libsslpp_a_METASOURCES = AUTO -libsslpp_a_SOURCES = sslengine.cpp sslcert.cpp sslerror.cpp sslconnection.cpp sslcontext.cpp +libsslpp_a_SOURCES = sslengine.cpp sslcert.cpp sslerror.cpp sslconnection.cpp sslcontext.cpp sslocspstapling.cpp ####### kdevelop will overwrite this part!!! (end)############ diff --git a/src/sslpp/Makefile.in b/src/sslpp/Makefile.in index 8b99f5263..445968e7b 100644 --- a/src/sslpp/Makefile.in +++ b/src/sslpp/Makefile.in @@ -69,7 +69,7 @@ libsslpp_a_AR = $(AR) $(ARFLAGS) libsslpp_a_LIBADD = am_libsslpp_a_OBJECTS = sslengine.$(OBJEXT) sslcert.$(OBJEXT) \ sslerror.$(OBJEXT) sslconnection.$(OBJEXT) \ - sslcontext.$(OBJEXT) + sslcontext.$(OBJEXT) sslocspstapling.$(OBJEXT) libsslpp_a_OBJECTS = $(am_libsslpp_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -203,7 +203,7 @@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libsslpp.a INCLUDES = -I$(top_srcdir)/src libsslpp_a_METASOURCES = AUTO -libsslpp_a_SOURCES = sslengine.cpp sslcert.cpp sslerror.cpp sslconnection.cpp sslcontext.cpp +libsslpp_a_SOURCES = sslengine.cpp sslcert.cpp sslerror.cpp sslconnection.cpp sslcontext.cpp sslocspstapling.cpp all: all-am .SUFFIXES: @@ -257,6 +257,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sslcontext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sslengine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sslerror.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sslocspstapling.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/sslpp/sslconnection.cpp b/src/sslpp/sslconnection.cpp index bfb061dd4..c5fe1b52c 100644 --- a/src/sslpp/sslconnection.cpp +++ b/src/sslpp/sslconnection.cpp @@ -24,6 +24,7 @@ #include #include #include +#include static const char * s_pErrInvldSSL = "Invalid Parameter, SSL* ssl is null\n"; @@ -146,6 +147,7 @@ int SSLConnection::flush() BIO * pBIO = SSL_get_wbio( m_ssl ); if ( !pBIO ) return 0; + m_iWant = 0; int ret = BIO_flush( pBIO ); if ( ret != 1 ) //1 means BIO_flush succeed. { @@ -195,6 +197,7 @@ int SSLConnection::accept() int ret = SSL_accept( m_ssl ); if ( ret == 1 ) { + //printf("%d\n", getSpdyVersion()); m_iStatus = CONNECTED; return ret; } @@ -275,6 +278,26 @@ SSL_SESSION * SSLConnection::getSession() const const char * SSLConnection::getVersion() const { return SSL_get_version( m_ssl ); } +int SSLConnection::getSpdyVersion() +{ + int v = 0; + +#ifdef LS_ENABLE_SPDY +#ifdef TLSEXT_TYPE_next_proto_neg + const char * NEXT_PROTO_NEGOTIATED_PREFIX = "spdy/"; + unsigned int len; + const unsigned char *data; + SSL_get0_next_proto_negotiated(m_ssl, &data, &len); + if (len > strlen(NEXT_PROTO_NEGOTIATED_PREFIX) && + strncasecmp((const char *)data, NEXT_PROTO_NEGOTIATED_PREFIX, strlen(NEXT_PROTO_NEGOTIATED_PREFIX)) == 0) { + v = data[strlen(NEXT_PROTO_NEGOTIATED_PREFIX)] - '0' -1; + return v; + } +#endif +#endif + return v; +} + int SSLConnection::getSessionIdLen( SSL_SESSION * s ) { return s->session_id_length; } diff --git a/src/sslpp/sslconnection.h b/src/sslpp/sslconnection.h index 675784b01..b2395bd4e 100644 --- a/src/sslpp/sslconnection.h +++ b/src/sslpp/sslconnection.h @@ -95,7 +95,9 @@ class SSLConnection SSL_SESSION * getSession() const; const char * getVersion() const; - + + int getSpdyVersion(); + static int getSessionIdLen( SSL_SESSION * s ); static const unsigned char * getSessionId( SSL_SESSION * s ); static int getCipherBits( const SSL_CIPHER * pCipher, int *algkeysize ); diff --git a/src/sslpp/sslcontext.cpp b/src/sslpp/sslcontext.cpp index 2981910c0..77aac5f49 100644 --- a/src/sslpp/sslcontext.cpp +++ b/src/sslpp/sslcontext.cpp @@ -29,79 +29,11 @@ #include #include #include - +#include +#include "sslocspstapling.h" //#include "http/vhostmap.h" - -static const SSL_METHOD* getMethod( int iMethod ) -{ - switch( iMethod ) - { - //case SSLContext::SSL_v2: - // return SSLv2_method(); - case SSLContext::SSL_v3: - return SSLv3_method(); - case SSLContext::SSL_TLSv1: - return TLSv1_method(); - case SSLContext::SSL_ALL: - default: - return SSLv23_method(); - } -} - -/* -static SSL_METHOD* getServerMethod( int iMethod ) -{ - switch( iMethod ) - { - case SSL_Context::SSL_v2: - meth = SSLv2_server_method(); - break; - case SSL_Context::SSL_v3: - meth = SSLv3_server_method(); - break; - case SSL_Context::SSL_TLSv1: - meth = TLSv1_server_method(); - break; - case SSL_Context::SSL_all: - default: - meth = SSLv23_server_method(); - } -} - -static SSL_METHOD* getClientMethod( int iMethod ) -{ - switch( iMethod ) - { - case SSL_Context::SSL_v2: - meth = SSLv2_client_method(); - break; - case SSL_Context::SSL_v3: - meth = SSLv3_client_method(); - break; - case SSL_Context::SSL_TLSv1: - meth = TLSv1_client_method(); - break; - case SSL_Context::SSL_all: - default: - meth = SSLv23_client_method(); - } -} -int SSLContext::initServer( int iMethod) -{ - SSL_METHOD * meth; - if ( s_pCtx == NULL ) - { - SSL_load_error_strings(); - SSLeay_add_ssl_algorithms(); - meth = getServerMethod( iMethod ); - s_pCtx = SSL_CTX_new (meth); - } -} -SSL_MODE_ENABLE_PARTIAL_WRITE -*/ - long SSLContext::setOptions( long options ) { return SSL_CTX_set_options( m_pCtx, options ); @@ -178,50 +110,78 @@ static void SSLConnection_ssl_info_cb( const SSL *pSSL, int where, int ret) } } +void SSLContext::setProtocol( int method ) +{ + if ( method == m_iMethod ) + return; + if ( ( method & SSL_ALL ) == 0 ) + return; + m_iMethod = method; + updateProtocol( method ); +} + + +void SSLContext::updateProtocol( int method ) +{ + setOptions( SSL_OP_NO_SSLv2 ); + if ( !(method & SSL_v3) ) + setOptions( SSL_OP_NO_SSLv3 ); + if ( !(method & SSL_TLSv1 ) ) + setOptions( SSL_OP_NO_TLSv1 ); +#ifdef SSL_OP_NO_TLSv1_1 + if ( !(method & SSL_TLSv11 ) ) + setOptions( SSL_OP_NO_TLSv1_1 ); +#endif +#ifdef SSL_OP_NO_TLSv1_2 + if ( !(method & SSL_TLSv12 ) ) + setOptions( SSL_OP_NO_TLSv1_2 ); +#endif +} int SSLContext::init( int iMethod ) { - if ( m_pCtx == NULL ) + if ( m_pCtx != NULL ) + return 0; + SSL_METHOD * meth; + if ( initSSL() ) + return -1; + m_iMethod = iMethod; + m_iEnableSpdy = 0; + meth = (SSL_METHOD *)SSLv23_method(); + m_pCtx = SSL_CTX_new (meth); + if ( m_pCtx ) { - SSL_METHOD * meth; - if ( initSSL() ) - return -1; - m_iMethod = iMethod; - meth = (SSL_METHOD*)getMethod( iMethod ); - m_pCtx = SSL_CTX_new (meth); - if ( m_pCtx ) - { #ifdef SSL_OP_NO_COMPRESSION - /* OpenSSL >= 1.0 only */ - SSL_CTX_set_options(m_pCtx, SSL_OP_NO_COMPRESSION); + /* OpenSSL >= 1.0 only */ + SSL_CTX_set_options(m_pCtx, SSL_OP_NO_COMPRESSION); #endif - setOptions( SSL_OP_SINGLE_DH_USE|SSL_OP_ALL ); - //setOptions( SSL_OP_NO_SSLv2 ); - setOptions( SSL_OP_NO_SSLv2 ); + setOptions( SSL_OP_SINGLE_DH_USE|SSL_OP_ALL ); + //setOptions( SSL_OP_NO_SSLv2 ); + updateProtocol( iMethod ); - setOptions( SSL_OP_CIPHER_SERVER_PREFERENCE); + setOptions( SSL_OP_CIPHER_SERVER_PREFERENCE); - SSL_CTX_set_mode( m_pCtx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); - if ( m_iRenegProtect ) - { - setOptions( SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION ); - SSL_CTX_set_info_callback( m_pCtx, SSLConnection_ssl_info_cb ); - } - return 0; - } - else + SSL_CTX_set_mode( m_pCtx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); + if ( m_iRenegProtect ) { - //FIXME: log ssl error - return -1; + setOptions( SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION ); + SSL_CTX_set_info_callback( m_pCtx, SSLConnection_ssl_info_cb ); } + return 0; + } + else + { + //FIXME: log ssl error + return -1; } - return 0; } SSLContext::SSLContext( int iMethod ) : m_pCtx( NULL ) , m_iMethod( iMethod ) , m_iRenegProtect( 1 ) + , m_iEnableSpdy( 0 ) + , m_pStapling( NULL ) { } SSLContext::~SSLContext() @@ -238,6 +198,8 @@ void SSLContext::release() m_pCtx = NULL; SSL_CTX_free( pCtx ); } + if ( m_pStapling ) + delete m_pStapling; } @@ -261,57 +223,60 @@ static int translateType( int type ) } } -static bool isFileChanged( const char * pFile, const struct stat &stOld ) +static int isFileChanged( const char * pFile, const struct stat &stOld ) { struct stat st; if ( ::stat( pFile, &st ) == -1 ) - return false; + return 0; return ((st.st_size != stOld.st_size)|| (st.st_ino != stOld.st_ino )|| (st.st_mtime != stOld.st_mtime )); } -bool SSLContext::isKeyFileChanged( const char * pKeyFile ) const +int SSLContext::isKeyFileChanged( const char * pKeyFile ) const { return isFileChanged( pKeyFile, m_stKey ); } -bool SSLContext::isCertFileChanged( const char * pCertFile ) const + +int SSLContext::isCertFileChanged( const char * pCertFile ) const { return isFileChanged( pCertFile, m_stCert ); } -bool SSLContext::setKeyCertificateFile( const char * pFile, int iType, int chained ) +int SSLContext::setKeyCertificateFile( const char * pFile, int iType, int chained ) { return setKeyCertificateFile( pFile, iType, pFile, iType, chained ); } -bool SSLContext::setKeyCertificateFile( const char * pKeyFile, int iKeyType, +int SSLContext::setKeyCertificateFile( const char * pKeyFile, int iKeyType, const char * pCertFile, int iCertType, int chained ) { if ( !setCertificateFile( pCertFile, iCertType, chained ) ) - return false; + return 0; if ( !setPrivateKeyFile( pKeyFile, iKeyType ) ) - return false; - return SSL_CTX_check_private_key( m_pCtx ) == 1; + return 0; + return SSL_CTX_check_private_key( m_pCtx ); } -bool SSLContext::setCertificateFile( const char * pFile, int type, int chained ) +int SSLContext::setCertificateFile( const char * pFile, int type, int chained ) { if ( !pFile ) - return false; + return 0; ::stat( pFile, &m_stCert ); if ( init( m_iMethod ) ) - return false; + return 0; + + // m_sCertfile.setStr( pFile ); if ( chained ) - return SSL_CTX_use_certificate_chain_file( m_pCtx, pFile ) == 1; + return SSL_CTX_use_certificate_chain_file( m_pCtx, pFile ); else return SSL_CTX_use_certificate_file( m_pCtx, pFile, - translateType( type ) ) == 1; + translateType( type ) ); } -bool SSLContext::setCertificateChainFile( const char * pFile ) +int SSLContext::setCertificateChainFile( const char * pFile ) { BIO *bio; X509 *x509; @@ -320,46 +285,56 @@ bool SSLContext::setCertificateChainFile( const char * pFile ) int n; if ((bio = BIO_new(BIO_s_file_internal())) == NULL) - return -1; + return 0; if (BIO_read_filename(bio, pFile) <= 0) { BIO_free(bio); - return -1; + return 0; } pExtraCerts=m_pCtx->extra_certs; - if ( pExtraCerts != NULL) { + if ( pExtraCerts != NULL) + { sk_X509_pop_free((STACK_OF(X509) *)pExtraCerts, X509_free); m_pCtx->extra_certs = NULL; } n = 0; - while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { - if (!SSL_CTX_add_extra_chain_cert(m_pCtx, x509)) { + while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) + { + if (!SSL_CTX_add_extra_chain_cert(m_pCtx, x509)) + { X509_free(x509); BIO_free(bio); - return -1; + return 0; } n++; } - if ((err = ERR_peek_error()) > 0) { + if ((err = ERR_peek_error()) > 0) + { if (!( ERR_GET_LIB(err) == ERR_LIB_PEM - && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { + && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) + { BIO_free(bio); - return -1; + return 0; } while (ERR_get_error() > 0) ; } + //m_sCertfile.setStr( pFile ); BIO_free(bio); return n > 0; } -bool SSLContext::setCALocation( const char * pCAFile, const char * pCAPath, int cv ) +int SSLContext::setCALocation( const char * pCAFile, const char * pCAPath, int cv ) { + int ret; if ( init( m_iMethod ) ) - return false; - int ret = SSL_CTX_load_verify_locations(m_pCtx, pCAFile, pCAPath); + return -1; + ret = SSL_CTX_load_verify_locations(m_pCtx, pCAFile, pCAPath); if ( (ret != 0) && cv ) { + + //m_sCAfile.setStr( pCAFile ); + ret = SSL_CTX_set_default_verify_paths( m_pCtx ); STACK_OF(X509_NAME) *pCAList = NULL; if ( pCAFile ) @@ -382,29 +357,29 @@ bool SSLContext::setCALocation( const char * pCAFile, const char * pCAPath, int SSL_CTX_set_client_CA_list( m_pCtx, pCAList ); } - return ret != 0; + return ret; } -bool SSLContext::setPrivateKeyFile( const char * pFile, int type ) +int SSLContext::setPrivateKeyFile( const char * pFile, int type ) { if ( !pFile ) - return false; + return 0; ::stat( pFile, &m_stKey ); if ( init( m_iMethod ) ) - return false; + return 0; return SSL_CTX_use_PrivateKey_file( m_pCtx, pFile, - translateType( type ) ) == 1; + translateType( type ) ); } -bool SSLContext::checkPrivateKey() +int SSLContext::checkPrivateKey() { if ( m_pCtx ) - return SSL_CTX_check_private_key( m_pCtx ) == 1; + return SSL_CTX_check_private_key( m_pCtx ); else - return false; + return 0; } -bool SSLContext::setCipherList( const char * pList ) +int SSLContext::setCipherList( const char * pList ) { if ( m_pCtx ) { @@ -419,10 +394,10 @@ bool SSLContext::setCipherList( const char * pList ) pList = cipher; } - return SSL_CTX_set_cipher_list( m_pCtx, pList ) == 1; + return SSL_CTX_set_cipher_list( m_pCtx, pList ); } else - return false; + return 0; } @@ -647,15 +622,13 @@ int SSLContext::initSNI( void * param ) #ifdef SSL_TLSEXT_ERR_OK SSL_CTX_set_tlsext_servername_callback( m_pCtx, SSLConnection_ssl_servername_cb ); SSL_CTX_set_tlsext_servername_arg( m_pCtx, param ); + return 0; #else return -1; #endif } - - - /*! \fn SSLContext::setClientVerify( int mode, int depth) */ @@ -703,3 +676,67 @@ int SSLContext::addCRL( const char * pCRLFile, const char * pCRLPath) X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); return 0; } + + +#ifdef LS_ENABLE_SPDY +static const char * NEXT_PROTO_STRING[3] = +{ + "\x06spdy/2\x08http/1.1\x08http/1.0", + "\x06spdy/3\x08http/1.1\x08http/1.0", + "\x06spdy/3\x06spdy/2\x08http/1.1\x08http/1.0" +}; + +static int NEXT_PROTO_STRING_LEN[3] = +{ + 25, 25, 32 +}; + +//static const char NEXT_PROTO_STRING[] = "\x06spdy/2\x08http/1.1\x08http/1.0"; + +static int SSLConnection_ssl_npn_advertised_cb(SSL *pSSL, const unsigned char **out, + unsigned int *outlen, void *arg) +{ + SSLContext * pCtx = (SSLContext *)arg; + *out = (const unsigned char *)NEXT_PROTO_STRING[ pCtx->getEnableSpdy() - 1 ]; + *outlen = NEXT_PROTO_STRING_LEN[ pCtx->getEnableSpdy() - 1 ]; + return SSL_TLSEXT_ERR_OK; +} + + +int SSLContext::enableSpdy( int level ) +{ + m_iEnableSpdy = ( level & 3 ); + if ( m_iEnableSpdy == 0 ) + return 0; +#ifdef TLSEXT_TYPE_next_proto_neg + SSL_CTX_set_next_protos_advertised_cb(m_pCtx, SSLConnection_ssl_npn_advertised_cb, this); +#else + #error "Openssl version is too low (openssl 1.0.1 or higher is required)!!!" +#endif + return 0; +} + +#else + int SSLContext::enableSpdy( int level ) + { + return -1; + } + +#endif + + +static int sslCertificateStatus_cb(SSL *ssl, void *data) +{ + SslOcspStapling* pStapling = (SslOcspStapling*)data; + return pStapling->callback( ssl ); +} + +int SSLContext::initStapling() +{ + if ( m_pStapling->init(m_pCtx) == -1 ) + return -1; + SSL_CTX_set_tlsext_status_cb(m_pCtx, sslCertificateStatus_cb); + SSL_CTX_set_tlsext_status_arg(m_pCtx, m_pStapling); + return 0; +} + diff --git a/src/sslpp/sslcontext.h b/src/sslpp/sslcontext.h index b20830580..6c68712ad 100644 --- a/src/sslpp/sslcontext.h +++ b/src/sslpp/sslcontext.h @@ -20,19 +20,23 @@ #include - +#include typedef struct ssl_st SSL; typedef struct ssl_ctx_st SSL_CTX; +class SslOcspStapling; class SSLContext { private: SSL_CTX* m_pCtx; short m_iMethod; - short m_iRenegProtect; - struct stat m_stKey; - struct stat m_stCert; + char m_iRenegProtect; + char m_iEnableSpdy; + struct stat m_stKey; + struct stat m_stCert; + + SslOcspStapling * m_pStapling; SSLContext( const SSLContext& rhs ) {} void operator=( const SSLContext& rhs ) {} @@ -40,41 +44,45 @@ class SSLContext void release(); int init( int method = SSL_ALL); static int seedRand(int len); + void updateProtocol( int method ); public: enum { - SSL_v2, - SSL_v3, - SSL_TLSv1, - SSL_ALL + SSL_v3 = 1, + SSL_TLSv1 = 2, + SSL_TLSv11 = 4, + SSL_TLSv12 = 8, + SSL_ALL = 15 }; enum { FILETYPE_PEM, FILETYPE_ASN1 }; + explicit SSLContext( int method = SSL_ALL ); ~SSLContext(); SSL_CTX* get() const { return m_pCtx; } SSL* newSSL(); - bool setKeyCertificateFile( const char * pKeyCertFile, int iType, + int setKeyCertificateFile( const char * pKeyCertFile, int iType, int chained ); - bool setKeyCertificateFile( const char * pKeyFile, int iKeyType, + int setKeyCertificateFile( const char * pKeyFile, int iKeyType, const char * pCertFile, int iCertType, int chained ); - bool setCertificateFile( const char * pFile, int type, int chained ); - bool setCertificateChainFile( const char * pFile ); - bool setPrivateKeyFile( const char * pFile, int type ); - bool checkPrivateKey(); + int setCertificateFile( const char * pFile, int type, int chained ); + int setCertificateChainFile( const char * pFile ); + int setPrivateKeyFile( const char * pFile, int type ); + int checkPrivateKey(); long setOptions( long options ); long setSessionCacheMode( long mode ); + void setProtocol( int method ); void setRenegProtect( int p ) { m_iRenegProtect = p; } - bool setCipherList( const char * pList ); - bool setCALocation( const char * pCAFile, const char * pCAPath, int cv ); + int setCipherList( const char * pList ); + int setCALocation( const char * pCAFile, const char * pCAPath, int cv ); - bool isKeyFileChanged( const char * pKeyFile ) const; - bool isCertFileChanged( const char * pCertFile ) const; + int isKeyFileChanged( const char * pKeyFile ) const; + int isCertFileChanged( const char * pCertFile ) const; int initSNI( void * param ); @@ -88,5 +96,10 @@ class SSLContext int len, char * decrypted, int bufLen ); void setClientVerify( int mode, int depth); int addCRL( const char * pCRLFile, const char * pCRLPath); + int enableSpdy( int level ); + int getEnableSpdy() const { return m_iEnableSpdy; } + SslOcspStapling * getpStapling () { return m_pStapling; } + void setpStapling (SslOcspStapling * pSslOcspStapling) { m_pStapling = pSslOcspStapling;} + int initStapling(); }; #endif diff --git a/src/sslpp/sslocspstapling.cpp b/src/sslpp/sslocspstapling.cpp new file mode 100644 index 000000000..a3280c256 --- /dev/null +++ b/src/sslpp/sslocspstapling.cpp @@ -0,0 +1,490 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static AutoStr2 s_ErrMsg = ""; +const char* getStaplingErrMsg(){ return s_ErrMsg.c_str(); } + +static void setLastErrMsg(const char *format, ...) +{ + const unsigned int MAX_LINE_LENGTH = 1024; + char s[MAX_LINE_LENGTH] = {0}; + va_list ap; + va_start( ap, format ); + int ret = vsnprintf( s, MAX_LINE_LENGTH, format, ap ); + va_end( ap ); + + if ( ( unsigned int )ret > MAX_LINE_LENGTH ) + ret = MAX_LINE_LENGTH; + s_ErrMsg.setLen(0); + s_ErrMsg.setStr(s,ret); +} + + +static unsigned int escapeBase64Uri(unsigned char *s, size_t size, unsigned char *d) +{ + unsigned char *begin = d; + while (size--) + { + if ( isalnum(*s) ) + *d++ = *s++; + else + { + *d++ = '%'; + *d++ = StringTool::s_hex[*s >> 4]; + *d++ = StringTool::s_hex[*s & 0x0f]; + s++; + } + } + return (unsigned int) (d - begin); +} + +static X509 * load_cert( const char * pPath ) +{ + X509 * pCert; + BIO * bio = BIO_new_file(pPath, "r"); + if ( bio == NULL ) + return NULL; + pCert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + BIO_free( bio ); + return pCert; +} + +static int OcspRespCb(void *pArg, HttpFetch *pHttpFetch) +{ + SslOcspStapling* pSslOcspStapling = (SslOcspStapling*)pArg; + pSslOcspStapling->processResponse(pHttpFetch); + return 0; +} + +int SslOcspStapling::callback(SSL *ssl) +{ + int iResult; + unsigned char* pbuff; + iResult = SSL_TLSEXT_ERR_NOACK; + if ( m_iDataLen > 0 ) + { + /*OpenSSL will free pbuff by itself */ + pbuff = (unsigned char*)malloc(m_iDataLen); + if ( pbuff == NULL ) + return SSL_TLSEXT_ERR_NOACK; + memcpy( pbuff, m_pRespData, m_iDataLen ); + SSL_set_tlsext_status_ocsp_resp(ssl, pbuff, m_iDataLen); + iResult = SSL_TLSEXT_ERR_OK; + } + update(); + return iResult; +} + +int SslOcspStapling::processResponse(HttpFetch *pHttpFetch) +{ + struct stat st; + const char *pRespContentType; + //assert( pHttpFetch == m_pHttpFetch ); + int istatusCode = m_pHttpFetch->getStatusCode() ; + pRespContentType = m_pHttpFetch->getRespContentType(); + if( ( istatusCode == 200) && (strcasecmp(pRespContentType, "application/ocsp-response") ==0)) + verifyRespFile(); + else + { + setLastErrMsg("Received bad OCSP response. ReponderUrl=%s, StatusCode=%d, ContentType=%s\n", + m_sOcspResponder.c_str(), istatusCode, ((pRespContentType)?(pRespContentType):(""))); + //printf("%s\n", s_ErrMsg.c_str()); + m_pHttpFetch->writeLog(s_ErrMsg.c_str()); + } + + if ( ::stat( m_sRespfileTmp.c_str(), &st ) == 0 ) + unlink( m_sRespfileTmp.c_str() ); + return 0; +} + +SslOcspStapling::SslOcspStapling() + : m_pHttpFetch( NULL ) + , m_iDataLen( 0 ) + , m_pRespData( NULL ) + , m_RespTime( 0 ) + , m_pCertId( NULL ) +{ +} + +SslOcspStapling::~SslOcspStapling() +{ + if ( m_pRespData != NULL ) + delete []m_pRespData; + if ( m_pHttpFetch != NULL) + delete m_pHttpFetch; + if ( m_pCertId != NULL) + OCSP_CERTID_free(m_pCertId); +} + +int SslOcspStapling::init(SSL_CTX* pSslCtx) +{ + int iResult; + X509* pCert; + struct timeval CurTime; + struct stat st; + m_pCtx = pSslCtx; + pCert = NULL; + iResult = -1; + + if ( ::stat( m_sRespfileTmp.c_str(), &st ) == 0 ) + { + gettimeofday( &CurTime, NULL ); + if ( (st.st_mtime + 30) <= CurTime.tv_sec ) + unlink( m_sRespfileTmp.c_str() ); + } + SSL_CTX_set_default_verify_paths( m_pCtx ); + + pCert = load_cert( m_sCertfile.c_str() ); + if ( pCert == NULL ) + { + setLastErrMsg("Failed to load file: %s!\n", m_sCertfile.c_str()); + return -1; + } + + if ( ( getCertId( pCert ) == 0 ) && ( getResponder( pCert ) == 0 )) + { + m_addrResponder.setHttpUrl(m_sOcspResponder.c_str(), m_sOcspResponder.len()); + iResult = update(); + } + X509_free( pCert ); + return iResult; +} + +int SslOcspStapling::update() +{ + + struct timeval CurTime; + struct stat st; + + gettimeofday( &CurTime, NULL ); + if ( ::stat( m_sRespfile.c_str(), &st ) == 0 ) + { + if ( (st.st_mtime + m_iocspRespMaxAge) > CurTime.tv_sec ) + { + if ( m_RespTime != st.st_mtime ) + { + verifyRespFile( 0 ); + m_RespTime = st.st_mtime; + } + return 0; + } + } + createRequest(); + return 0; +} + + +int SslOcspStapling::getResponder(X509* pCert) +{ + char *pUrl; + X509 *pCAt; +#if OPENSSL_VERSION_NUMBER >= 0x10000003L + STACK_OF(OPENSSL_STRING) *strResp; +#else + STACK *strResp; +#endif + if ( m_sOcspResponder.c_str() ) + { + return 0; + } + strResp = X509_get1_ocsp( pCert ); + if (strResp == NULL) + { + if ( m_sCAfile.c_str() == NULL) + return -1; + pCAt = load_cert( m_sCAfile.c_str() ); + if ( pCAt == NULL ) + { + setLastErrMsg("Failed to load file: %s!\n", m_sCAfile.c_str()); + return -1; + } + + strResp = X509_get1_ocsp(pCAt); + X509_free( pCAt ); + if ( strResp == NULL ) + { + setLastErrMsg("Failed to get responder!\n"); + return -1; + } + } +#if OPENSSL_VERSION_NUMBER >= 0x1000004fL + pUrl = sk_OPENSSL_STRING_value(strResp, 0); +#elif OPENSSL_VERSION_NUMBER >= 0x10000003L + pUrl = (char *)sk_value((const _STACK*) strResp, 0); +#else + pUrl = (char *)sk_value((const STACK*) strResp, 0); +#endif + if (pUrl ) + { + m_sOcspResponder.setStr( pUrl ); + return 0; + } + X509_email_free( strResp ); + setLastErrMsg("Failed to get responder Url!\n"); + return -1; +} + +int SslOcspStapling::getRequestData(unsigned char *pReqData) +{ + int len = -1; + OCSP_REQUEST *ocsp; + OCSP_CERTID *id; + + if ( m_pCertId == NULL ) + return -1; + ocsp = OCSP_REQUEST_new(); + if ( ocsp == NULL ) + return -1; + + id = OCSP_CERTID_dup(m_pCertId); + if ( OCSP_request_add0_id(ocsp, id) != NULL ) + { + len = i2d_OCSP_REQUEST(ocsp, &pReqData); + if ( len > 0 ) + { + *pReqData = 0; + } + } + OCSP_REQUEST_free(ocsp); + return len; +} + +int SslOcspStapling::createRequest() +{ + int len, len64, n1; + unsigned char *pReqData, *pReqData64; + unsigned char ReqData[4000], ReqData64[4000]; + struct stat st; + if ( ::stat( m_sRespfileTmp.c_str(), &st ) == 0 ) + return 0; + pReqData = ReqData; + pReqData64 = ReqData64; + len = getRequestData(pReqData); + if ( len <= 0 ) + return -1; + len64 = Base64::encode( (const char*)ReqData, len, (char*)pReqData64); + + const char* pUrl = m_sOcspResponder.c_str(); + memcpy( pReqData, pUrl, m_sOcspResponder.len()); + + pReqData += m_sOcspResponder.len(); + if ( pUrl[m_sOcspResponder.len() -1] != '/' ) + { + *pReqData++ = '/'; + } + + n1 = escapeBase64Uri( pReqData64, len64, pReqData); + pReqData += n1; + *pReqData = 0; + len = pReqData - ReqData; + + if ( m_pHttpFetch != NULL ) + delete m_pHttpFetch; + m_pHttpFetch = new HttpFetch(); + m_pHttpFetch->setCallBack( OcspRespCb, this); + m_pHttpFetch->setTimeout( 30 );//Set Req timeout as 30 seconds + m_pHttpFetch->startReq( (const char* )ReqData, 1, 1, NULL, 0, + m_sRespfileTmp.c_str(), NULL, m_addrResponder ); + setLastErrMsg("%lu, len = %d\n%s \n", m_pHttpFetch, len, ReqData); + //printf("%s\n", s_ErrMsg.c_str()); + return 0; +} + +void SslOcspStapling::updateRespData(OCSP_RESPONSE *pResponse) +{ + unsigned char * pbuff; + m_iDataLen = i2d_OCSP_RESPONSE(pResponse, NULL); + if ( m_iDataLen > 0) + { + if ( m_pRespData != NULL ) + delete [] m_pRespData; + + m_pRespData = new unsigned char[m_iDataLen]; + pbuff = m_pRespData; + m_iDataLen = i2d_OCSP_RESPONSE(pResponse, &(pbuff)); + if ( m_iDataLen <= 0) + { + m_iDataLen = 0; + delete [] m_pRespData; + m_pRespData = NULL; + } + } +} + +int SslOcspStapling::certVerify(OCSP_RESPONSE *pResponse, OCSP_BASICRESP *pBasicResp, X509_STORE *pXstore) +{ + int n, iResult = -1; + STACK_OF(X509) *pXchain; + ASN1_GENERALIZEDTIME *pThisupdate, *pNextupdate; + struct stat st; + + pXchain = m_pCtx->extra_certs; + if ( OCSP_basic_verify(pBasicResp, pXchain, pXstore, OCSP_TRUSTOTHER) == 1 ) + { + if ( (m_pCertId != NULL) + && (OCSP_resp_find_status(pBasicResp, m_pCertId, &n, + NULL, NULL,&pThisupdate, &pNextupdate) == 1) + && (n == V_OCSP_CERTSTATUS_GOOD) + && (OCSP_check_validity(pThisupdate, pNextupdate, 300, -1) == 1) ) + { + iResult = 0; + updateRespData(pResponse); + unlink( m_sRespfile.c_str()); + rename( m_sRespfileTmp.c_str(), m_sRespfile.c_str()); + if ( ::stat( m_sRespfile.c_str(), &st ) == 0 ) + m_RespTime = st.st_mtime; + } + } + return iResult; +} + +int SslOcspStapling::verifyRespFile(int iNeedVerify) +{ + int iResult = -1; + BIO *pBio; + OCSP_RESPONSE *pResponse; + OCSP_BASICRESP *pBasicResp; + X509_STORE *pXstore; + if ( iNeedVerify ) + pBio = BIO_new_file(m_sRespfileTmp.c_str(), "r"); + else + pBio = BIO_new_file(m_sRespfile.c_str(), "r"); + if ( pBio == NULL ) + return -1; + + pResponse = d2i_OCSP_RESPONSE_bio(pBio, NULL); + BIO_free( pBio ); + if ( pResponse == NULL ) + return -1; + + if ( OCSP_response_status(pResponse) == OCSP_RESPONSE_STATUS_SUCCESSFUL) + { + if ( iNeedVerify ) + { + pBasicResp = OCSP_response_get1_basic(pResponse); + if ( pBasicResp != NULL ) + { + pXstore = SSL_CTX_get_cert_store(m_pCtx); + if (pXstore) + iResult = certVerify( pResponse, pBasicResp, pXstore ); + OCSP_BASICRESP_free( pBasicResp ); + } + } + else + { + updateRespData(pResponse); + iResult = 0; + } + } + OCSP_RESPONSE_free( pResponse ); + return iResult; +} + +int SslOcspStapling::getCertId(X509* pCert) +{ + int i, n; + X509 *pXissuer; + X509_STORE *pXstore; + STACK_OF(X509) *pXchain; + X509_STORE_CTX *pXstore_ctx; + + + pXchain = m_pCtx->extra_certs; + n = sk_X509_num(pXchain); + for ( i = 0; i < n; i++ ) + { + pXissuer = sk_X509_value(pXchain, i); + if ( X509_check_issued(pXissuer, pCert) == X509_V_OK ) + { + CRYPTO_add(&pXissuer->references, 1, CRYPTO_LOCK_X509); + m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer); + X509_free( pXissuer ); + return 0; + } + } + pXstore = SSL_CTX_get_cert_store(m_pCtx); + if (pXstore == NULL) + { + setLastErrMsg("SSL_CTX_get_cert_store failed!\n"); + return -1; + } + pXstore_ctx = X509_STORE_CTX_new(); + if (pXstore_ctx == NULL) + { + setLastErrMsg("X509_STORE_CTX_new failed!\n"); + return -1; + } + if (X509_STORE_CTX_init(pXstore_ctx, pXstore, NULL, NULL) == 0) + { + setLastErrMsg("X509_STORE_CTX_init failed!\n"); + return -1; + } + n = X509_STORE_CTX_get1_issuer(&pXissuer, pXstore_ctx, pCert); + X509_STORE_CTX_free(pXstore_ctx); + if ( (n == -1) || (n == 0) ) + { + setLastErrMsg("X509_STORE_CTX_get1_issuer failed!\n"); + return -1; + } + m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer); + X509_free( pXissuer ); + return 0; +} + +void SslOcspStapling::setCertFile( const char* Certfile ) +{ + char RespFile[4096]; + unsigned char md5[16]; + char md5Str[35] = {0}; + m_sCertfile.setStr( Certfile ); + StringTool::getMd5(Certfile, strlen(Certfile), md5); + StringTool::hexEncode((const char *)md5, 16, md5Str); + md5Str[32] = 0; + RespFile[0] = 0; + strcat(RespFile, HttpGlobals::s_pServerRoot); + strcat(RespFile, "/tmp/ocspcache/R"); + strcat(RespFile, md5Str); + strcat(RespFile, ".rsp"); + m_sRespfile.setStr( RespFile ); + strcat(RespFile, ".tmp"); + m_sRespfileTmp.setStr( RespFile ); +} diff --git a/src/sslpp/sslocspstapling.h b/src/sslpp/sslocspstapling.h new file mode 100644 index 000000000..d86507d30 --- /dev/null +++ b/src/sslpp/sslocspstapling.h @@ -0,0 +1,81 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + + +#ifndef SSLOCSPSTAPLING_H +#define SSLOCSPSTAPLING_H +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +class HttpFetch; + +class SslOcspStapling +{ +public: + SslOcspStapling(); + ~SslOcspStapling(); + int init(SSL_CTX* pSslCtx); + int update(); + int getCertId(X509* pCert); + int createRequest(); + int getResponder( X509* pCert ); + int callback(SSL *ssl); + int processResponse(HttpFetch *pHttpFetch); + int verifyRespFile( int iNeedVerify = 1 ); + int certVerify(OCSP_RESPONSE *pResponse, OCSP_BASICRESP *pBasicResp, X509_STORE *pXstore); + void updateRespData(OCSP_RESPONSE *pResponse); + int getRequestData(unsigned char *pReqData); + void setCertFile( const char* Certfile ); + + void setOcspResponder( const char* url ) { m_sOcspResponder.setStr( url ); } + void setCombineCAfile( const char* CAfile ) { m_sCombineCAfile.setStr( CAfile ); } + void setCAFile( const char* CAfile ) { m_sCAfile.setStr( CAfile ); } + void setRespMaxAge( const int iMaxAge ) { m_iocspRespMaxAge = iMaxAge; } + void setRespfile( const char* Respfile ) { m_sRespfile.setStr( Respfile ); } + +private: + HttpFetch* m_pHttpFetch; + + uint32_t m_iDataLen; + unsigned char* m_pRespData; + GSockAddr m_addrResponder; + + AutoStr2 m_sCertfile; + AutoStr2 m_sCAfile; + AutoStr2 m_sOcspResponder; + AutoStr2 m_sCombineCAfile; + AutoStr2 m_sRespfile; + AutoStr2 m_sRespfileTmp; + int m_iocspRespMaxAge; + SSL_CTX* m_pCtx; + time_t m_RespTime; + OCSP_CERTID* m_pCertId; + +}; +const char* getStaplingErrMsg(); +#endif // SSLOCSPSTAPLING_H diff --git a/src/test/http/chunkostest.cpp b/src/test/http/chunkostest.cpp index c495bcb83..627ef04aa 100644 --- a/src/test/http/chunkostest.cpp +++ b/src/test/http/chunkostest.cpp @@ -45,7 +45,7 @@ class TestOS : public OutputStream } int writev( IOVec& iov, int total ) { - return OutputStream::writev( iov ); + return OutputStream::writevToWrite( iov ); } void clearCache() diff --git a/src/test/http/httpbuftest.cpp b/src/test/http/httpbuftest.cpp index 5e24411c6..4bb9778fc 100644 --- a/src/test/http/httpbuftest.cpp +++ b/src/test/http/httpbuftest.cpp @@ -24,7 +24,7 @@ TEST(HttpBufTest_test) { - HttpBuf buf; + AutoBuf buf; CHECK( 0 == buf.size() ); CHECK( 0 < buf.capacity() ); CHECK( 0 == buf.reserve(0) ); diff --git a/src/test/http/httpcgitooltest.cpp b/src/test/http/httpcgitooltest.cpp index b5e74e721..0b53fa9de 100644 --- a/src/test/http/httpcgitooltest.cpp +++ b/src/test/http/httpcgitooltest.cpp @@ -23,79 +23,79 @@ #include #include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" -TEST( HttpCgiToolTest_test) -{ - HttpConnection conn; - HttpExtConnector connector; - connector.setHttpConn( &conn ); - conn.getReq()->reset(); - char test1[] = - "staTus: 404 not found \t \r \n" - "Content-Type: \tapplication/x-testcgi \n" - "Script-Control: no-abort \n" - "Http-eXtended:my-extension\n" - "MultiLineHeader: line1\n" - " line2\r\n" - "\n" - "this is the resp body"; - char * pEnd = test1 + strlen( test1 ); - char * pCur = test1; - char * pBuf = test1; - int status = 0; - while( pCur < pEnd ) - { - pCur++; - int ret = HttpCgiTool::parseRespHeader( &connector, pBuf, pCur - pBuf, status ); - if ( ret > 0 ) - pBuf += ret; - if ( status == HttpReq::HEADER_OK ) - break; - } - - CHECK( strncmp( pBuf, "this is the resp body", 21 ) == 0 ); - CHECK( conn.getReq()->getStatusCode() == SC_404 ); - conn.getResp()->getOutputBuf().append( '\0' ); - const char * pOutput = conn.getResp()->getOutputBuf().begin(); - CHECK( strstr( pOutput, - "Content-Type: \tapplication/x-testcgi\r\n" ) != NULL ); - CHECK( strstr( pOutput, - "Http-eXtended:my-extension\r\n" ) != NULL ); - CHECK( strstr( pOutput, "MultiLineHeader: line1\r\n" - " line2\r\n" ) != NULL ); - CHECK( *conn.getReq()->getLocation() == 0 ); - - char test2[] = "Location: http://www.somewhere.com/\n\n"; - status = 0; - conn.getResp()->reset(); - conn.getReq()->setStatusCode( SC_200 ); - int ret = HttpCgiTool::parseRespHeader( &connector, test2, strlen( test2 ), status ); - CHECK( ret == (int)strlen( test2 ) ); - CHECK( status == HttpReq::HEADER_OK ); - CHECK( conn.getReq()->getStatusCode() == SC_302 ); - conn.getResp()->getOutputBuf().append( '\0' ); - pOutput = conn.getResp()->getOutputBuf().begin(); - - CHECK( strstr( pOutput, - "Location: http://www.somewhere.com/\r\n" ) != NULL ); - CHECK( *conn.getReq()->getLocation() == 0 ); - - char test3[] = "Location: /internal/redirect/url\n\n"; - status = 0; - conn.getResp()->reset(); - conn.getReq()->setStatusCode( SC_200 ); - ret = HttpCgiTool::parseRespHeader( &connector, test3, strlen( test3 ), status ); - CHECK( ret == (int)strlen( test3 ) ); - CHECK( status == HttpReq::HEADER_OK ); - CHECK( conn.getReq()->getStatusCode() == SC_200 ); - conn.getResp()->getOutputBuf().append( '\0' ); - pOutput = conn.getResp()->getOutputBuf().begin(); - - CHECK( strstr( pOutput, - "/internal/redirect/url" ) == NULL ); - CHECK( strcmp( "/internal/redirect/url", - conn.getReq()->getLocation()) == 0 ); - - -} +// TEST( HttpCgiToolTest_test) +// { +// HttpConnection conn; +// HttpExtConnector connector; +// connector.setHttpConn( &conn ); +// conn.getReq()->reset(); +// char test1[] = +// "staTus: 404 not found \t \r \n" +// "Content-Type: \tapplication/x-testcgi \n" +// "Script-Control: no-abort \n" +// "Http-eXtended:my-extension\n" +// "MultiLineHeader: line1\n" +// " line2\r\n" +// "\n" +// "this is the resp body"; +// char * pEnd = test1 + strlen( test1 ); +// char * pCur = test1; +// char * pBuf = test1; +// int status = 0; +// while( pCur < pEnd ) +// { +// pCur++; +// int ret = HttpCgiTool::parseRespHeader( &connector, pBuf, pCur - pBuf, status ); +// if ( ret > 0 ) +// pBuf += ret; +// if ( status == HttpReq::HEADER_OK ) +// break; +// } +// +// CHECK( strncmp( pBuf, "this is the resp body", 21 ) == 0 ); +// CHECK( conn.getReq()->getStatusCode() == SC_404 ); +// conn.getResp()->getOutputBuf().append( '\0' ); +// const char * pOutput = conn.getResp()->getOutputBuf().begin(); +// CHECK( strstr( pOutput, +// "Content-Type: \tapplication/x-testcgi\r\n" ) != NULL ); +// CHECK( strstr( pOutput, +// "Http-eXtended:my-extension\r\n" ) != NULL ); +// CHECK( strstr( pOutput, "MultiLineHeader: line1\r\n" +// " line2\r\n" ) != NULL ); +// CHECK( *conn.getReq()->getLocation() == 0 ); +// +// char test2[] = "Location: http://www.somewhere.com/\n\n"; +// status = 0; +// conn.getResp()->reset(); +// conn.getReq()->setStatusCode( SC_200 ); +// int ret = HttpCgiTool::parseRespHeader( &connector, test2, strlen( test2 ), status ); +// CHECK( ret == (int)strlen( test2 ) ); +// CHECK( status == HttpReq::HEADER_OK ); +// CHECK( conn.getReq()->getStatusCode() == SC_302 ); +// conn.getResp()->getOutputBuf().append( '\0' ); +// pOutput = conn.getResp()->getOutputBuf().begin(); +// +// CHECK( strstr( pOutput, +// "Location: http://www.somewhere.com/\r\n" ) != NULL ); +// CHECK( *conn.getReq()->getLocation() == 0 ); +// +// char test3[] = "Location: /internal/redirect/url\n\n"; +// status = 0; +// conn.getResp()->reset(); +// conn.getReq()->setStatusCode( SC_200 ); +// ret = HttpCgiTool::parseRespHeader( &connector, test3, strlen( test3 ), status ); +// CHECK( ret == (int)strlen( test3 ) ); +// CHECK( status == HttpReq::HEADER_OK ); +// CHECK( conn.getReq()->getStatusCode() == SC_200 ); +// conn.getResp()->getOutputBuf().append( '\0' ); +// pOutput = conn.getResp()->getOutputBuf().begin(); +// +// CHECK( strstr( pOutput, +// "/internal/redirect/url" ) == NULL ); +// CHECK( strcmp( "/internal/redirect/url", +// conn.getReq()->getLocation()) == 0 ); +// +// +// } #endif diff --git a/src/test/http/httpheadertest.cpp b/src/test/http/httpheadertest.cpp index ac1d9d5ac..d677e2689 100644 --- a/src/test/http/httpheadertest.cpp +++ b/src/test/http/httpheadertest.cpp @@ -16,9 +16,10 @@ * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ #ifdef RUN_TEST - +#include #include "httpheadertest.h" #include +#include #include #include @@ -247,6 +248,231 @@ TEST(benchmarkLookup) } } +#include +void DisplayHeader(IOVec io, int format, short count) +{ + IOVec::iterator it; + unsigned char *p = NULL; + for (it = io.begin(); it != io.end(); ++it) + { + p = (unsigned char *)it->iov_base; + for (unsigned int i=0; iiov_len; ++i) + { + if (format != 0) + printf("%02X ",p[i]); + else + printf("%c",p[i]); + } + } + printf("\r\nCount = %d\r\n======================================================\r\n", count); + + if (format != 0) + { + AutoBuf buf; + for (it = io.begin(); it != io.end(); ++it) + { + buf.append( (const char *)it->iov_base, it->iov_len); + } + + if (format == 1) + { + char *p = buf.begin(); + short *tempNumS; + short tempNum; + + for (int j=0; jgetMIME()->c_str(), "application/msword") == 0 ); diff --git a/src/test/http/httprangetest.cpp b/src/test/http/httprangetest.cpp index 103c82839..d599eafaa 100644 --- a/src/test/http/httprangetest.cpp +++ b/src/test/http/httprangetest.cpp @@ -70,7 +70,7 @@ TEST(Test_httprangetest) CHECK( range.getContentRangeString( 4, crs, 38 ) == 37); CHECK( strcmp( crs, "Content-Range: bytes 1999-1999/2000\r\n" ) == 0 ); CHECK( range.getContentRangeString( 5, crs, 30 ) == 29); - CHECK( strcmp( crs, "Content-Range: bytes *\/2000\r\n" ) == 0 ); + CHECK( strcmp( crs, "Content-Range: bytes */2000\r\n" ) == 0 ); CHECK( range.getContentRangeString( 4, crs, 37 ) == -1); CHECK( range.getContentRangeString( 5, crs, 29 ) == -1); diff --git a/src/test/http/httpreqtest.cpp b/src/test/http/httpreqtest.cpp index 16f9f99fd..ea007bee3 100644 --- a/src/test/http/httpreqtest.cpp +++ b/src/test/http/httpreqtest.cpp @@ -32,7 +32,10 @@ class HttpReqTst : public HttpReq, public LogTracker public: HttpReqTst() : HttpReq( ) - { setILog( this ); } + { } + const char * getLogId() { return LogTracker::getLogId(); } + virtual const char * buildLogId() { return getLogId(); } + int append( const char * pBuf, int size ) { return HttpReq::appendTestHeaderData( pBuf, size ); } }; @@ -59,7 +62,7 @@ TEST(HttpReqTest_testFragment) "\r\n" "parentWin=YB_conf&objName=ESgeneral&objId=&finishPage=servGeneral.php%3Fid%3D1&nextPage=servGeneral1.php\r\n"; HttpReqTst req; - req.getIDBuf() = "testFragment" ; + req.getIdBuf() = "testFragment" ; req.reset(); req.setVHost( (const HttpVHost *)1 ); //just skip vhost lookup while parsing header CHECK( 1 == req.append( pFrag1, strlen( pFrag1 ) )); @@ -108,7 +111,7 @@ TEST( HttpReqTest_testParseHeader) "\t \tline3\r\n" "\r\n"; HttpReqTst req; - req.getIDBuf() = "testParseHeader"; + req.getIdBuf() = "testParseHeader"; req.reset(); req.setVHost( (const HttpVHost *)1 ); //just skip vhost look while parsing header CHECK( 1 == req.append( pGarbage, strlen( pGarbage ) )); @@ -196,7 +199,7 @@ TEST( HttpReqTest_testParseHeader1) "\t close\r\n" "\r\n"; HttpReqTst req; - req.getIDBuf() = "testParseHeader1" ; + req.getIdBuf() = "testParseHeader1" ; req.reset(); req.setVHost( (const HttpVHost *)1 ); //just skip vhost look while parsing header @@ -264,7 +267,7 @@ TEST( HttpReqTest_testParseHeader2) "Connection: close\r\n\r\n" }; HttpReqTst req; - req.getIDBuf() = "testParseHeader1" ; + req.getIdBuf() = "testParseHeader1" ; req.reset(); req.setVHost( (const HttpVHost *)1 ); //just skip vhost look while parsing header @@ -326,7 +329,7 @@ TEST( HttpReqTest_testParseHeader3) "Connection: close\r\n\r\n" }; HttpReqTst req; - req.getIDBuf() = "testParseHeader1" ; + req.getIdBuf() = "testParseHeader1" ; req.reset(); req.setVHost( (const HttpVHost *)1 ); //just skip vhost look while parsing header diff --git a/src/test/spdy/CMakeLists.txt b/src/test/spdy/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/test/spdy/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/src/test/spdy/dummiostream.cpp b/src/test/spdy/dummiostream.cpp new file mode 100644 index 000000000..b3fc8697d --- /dev/null +++ b/src/test/spdy/dummiostream.cpp @@ -0,0 +1,99 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifdef RUN_TEST +#include "dummyiostream.h" +#include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" +DummySpdyConnStream::DummySpdyConnStream() + :m_pDatabuff(NULL) + ,m_Datalen(0) +{ +} +DummySpdyConnStream::DummySpdyConnStream(char* buff, int length) +{ + m_pDatabuff = buff; + m_Datalen = length; + //m_InputBuff.append(m_pDatabuff, length); + SpdyConnection * pConn = new SpdyConnection(); + pConn->assignStream(this); + pConn->init( HIOS_PROTO_SPDY2 ); + onInitConnected(); +} + +int DummySpdyConnStream::read( char * buf, int len ) +{ + if ( m_InputBuff.empty() ) + return 0; + *buf = *m_InputBuff.begin(); + m_InputBuff.pop_front( 1 ); + return 1; +} + +int DummySpdyConnStream::write( const char * buf, int len ) +{ + return len; +} + +int DummySpdyConnStream::onInitConnected() +{ + getHandler()->onInitConnected(); + m_running = 1; + eventLoop(); + return 0; +} + +int DummySpdyConnStream::sendHeaders( IOVec &vector, int headerCount ) +{ + //TODO: + return -1; +} + + +int DummySpdyConnStream::eventLoop() +{ + int lenInBuff = 0; + int length; + + while( m_running ) + { + if(m_InputBuff.empty()) + { + length = m_Datalen - lenInBuff; + if(length == 0) + { + m_running = 0; + continue; + } + if(length >80) + length = 80; + m_InputBuff.append(m_pDatabuff + lenInBuff, length); + lenInBuff += length; + + } + if ( isWantRead() && !m_InputBuff.empty()) + { + getHandler()->onReadEx(); + } + if ( isWantWrite() ) + getHandler()->onWriteEx(); + + } + return 0; +} + + +#endif \ No newline at end of file diff --git a/src/test/spdy/dummyiostream.h b/src/test/spdy/dummyiostream.h new file mode 100644 index 000000000..2bf6a6e76 --- /dev/null +++ b/src/test/spdy/dummyiostream.h @@ -0,0 +1,62 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef DUMMYIOSTREAM_H +#define DUMMYIOSTREAM_H +#include "spdy/spdyconnection.h" +#include "http/hiostream.h" +#include + +class DummySpdyConnStream: public HioStream +{ + int m_running; + char* m_pDatabuff; + int m_Datalen; + LoopBuf m_InputBuff; +public: + DummySpdyConnStream(); + DummySpdyConnStream(char* buff, int length); + ~DummySpdyConnStream(){}; + int read( char * buf, int len ); + int write( const char * buf, int len ); + int flush() { return -1; } + + //////////////////////////// + int writev( IOVec &vector, int total ) {return 0;}; + int sendfile( IOVec &vector, int &total, int fdSrc, off_t off, size_t size ) {return 0;}; + int close() { return -1;}; + int sendHeaders( IOVec &vector, int headerCount ); + + + void suspendRead() { setFlag( HIO_FLAG_WANT_READ, 0 ); } + void continueRead() { setFlag( HIO_FLAG_WANT_READ, 1 ); } + void suspendWrite(){return;}; + void continueWrite(){return;}; + void switchWriteToRead(){return;}; + void onTimer() {}; + uint32_t GetStreamID(){return 0;}; + virtual const char * buildLogId() { return getLogId(); } + + ///////////////////////////// +private: + void appendInputData( char * buff, int length ); + int eventLoop(); + int onInitConnected(); + +}; + +#endif // DUMMYIOSTREAM_H \ No newline at end of file diff --git a/src/test/spdy/spdyconnectiontest.cpp b/src/test/spdy/spdyconnectiontest.cpp new file mode 100644 index 000000000..c4712bb81 --- /dev/null +++ b/src/test/spdy/spdyconnectiontest.cpp @@ -0,0 +1,58 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifdef RUN_TEST + +#include +#include "spdy/spdyconnection.h" +#include "dummyiostream.h" +#include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" +unsigned char c2s_SYN_STREAM5[] = +{ + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x01,0x26,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x38,0xEA,0xDF,0xA2,0x51,0xB2,0x62,0xE0,0x66,0x60,0x83,0xA4,0x17,0x06, + 0x7B,0xB8,0x0B,0x75,0x30,0x2C,0xD6,0xAE,0x40,0x17,0xCD,0xCD,0xB1,0x2E,0xB4,0x35, + 0xD0,0xB3,0xD4,0xD1,0xD2,0xD7,0x02,0xB3,0x2C,0x18,0xF8,0x50,0x73,0x2C,0x83,0x9C, + 0x67,0xB0,0x3F,0xD4,0x3D,0x3A,0x60,0x07,0x81,0xD5,0x99,0xEB,0x40,0xD4,0x1B,0x33, + 0xF0,0xA3,0xE5,0x69,0x06,0x41,0x90,0x8B,0x75,0xA0,0x4E,0xD6,0x29,0x4E,0x49,0xCE, + 0x80,0xAB,0x81,0x25,0x03,0x06,0xBE,0xD4,0x3C,0xDD,0xD0,0x60,0x9D,0xD4,0x3C,0xA8, + 0xA5,0xBC,0x28,0x89,0x8D,0x81,0x13,0x20,0x80,0x72,0x13,0x2B,0x74,0x13,0xD3,0x53, + 0x6D,0x0D,0x00,0x02,0x88,0x81,0x05,0x94,0xFB,0x19,0xF8,0x40,0x49,0x24,0x07,0xC4, + 0xB4,0xB2,0x04,0x66,0x3A,0x06,0xB6,0x5C,0x60,0xA9,0x93,0x9F,0xC2,0xC0,0xEC,0xEE, + 0x1A,0xC2,0xC0,0x56,0x0C,0xD4,0x9B,0x9B,0x0A,0x54,0x5A,0x52,0x52,0xC0,0xC0,0x0C, + 0x0A,0x10,0x46,0x80,0x00,0xD2,0x07,0x08,0x20,0x06,0x2E,0x44,0x2E,0x66,0x48,0xF3, + 0xCD,0xAF,0xCA,0xCC,0xC9,0x49,0xD4,0x37,0xD5,0x33,0x50,0xD0,0x88,0x30,0x34,0xB4, + 0x56,0xF0,0xC9,0xCC,0x2B,0xAD,0x50,0xC8,0x34,0xB3,0x30,0xD3,0x54,0x70,0x04,0x06, + 0x49,0x6A,0x78,0x6A,0x92,0x77,0x66,0x89,0xBE,0xA9,0xB1,0xB9,0x9E,0xA1,0xA1,0x82, + 0x86,0xB7,0x47,0x88,0xAF,0x8F,0x8E,0x42,0x4E,0x66,0x76,0xAA,0x82,0x7B,0x6A,0x72, + 0x76,0xBE,0xA6,0x82,0x73,0x06,0xB0,0x30,0x4A,0xD5,0x37,0x32,0xD6,0x33,0xD0,0x33, + 0x34,0x32,0x37,0xD4,0xB3,0x34,0x57,0x08,0x4E,0x4C,0x4B,0x2C,0xCA,0x84,0xEA,0x62, + 0x60,0x87,0xC6,0x09,0x03,0x07,0x2C,0xAA,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x80,0x00,0x62,0xE0,0x82,0xC7,0x0C,0x33,0x30,0x8C,0x07,0x26,0x74,0xC9,0x0B,0x43, + 0x1E,0x80,0x00,0xD2,0x4F,0x4B,0x2C,0xCB,0x4C,0xCE,0xCF,0xD3,0xCB,0x4C,0xCE,0x07, + 0x08,0xA0,0x41,0x12,0x9C,0x00,0x00,0x00,0x00,0xFF,0xFF +}; +TEST(spdyconnection_test) +{ + //DummySpdyConnStream MyDummyHioStream((char*)c2s_SYN_STREAM5, sizeof(c2s_SYN_STREAM5)); +} +#endif \ No newline at end of file diff --git a/src/test/spdy/spdyzlibfiltertest.cpp b/src/test/spdy/spdyzlibfiltertest.cpp new file mode 100644 index 000000000..39bffebb9 --- /dev/null +++ b/src/test/spdy/spdyzlibfiltertest.cpp @@ -0,0 +1,183 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ + +#ifdef RUN_TEST + +#include +#include "spdy/spdyconnection.h" +#include "util/autobuf.h" +#include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" +unsigned char c2s_SYN_STREAM1[] = +{ + 0x80,0x02,0x00,0x01,0x01,0x00,0x01,0x26,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x38,0xEA,0xDF,0xA2,0x51,0xB2,0x62,0xE0,0x66,0x60,0x83,0xA4,0x17,0x06, + 0x7B,0xB8,0x0B,0x75,0x30,0x2C,0xD6,0xAE,0x40,0x17,0xCD,0xCD,0xB1,0x2E,0xB4,0x35, + 0xD0,0xB3,0xD4,0xD1,0xD2,0xD7,0x02,0xB3,0x2C,0x18,0xF8,0x50,0x73,0x2C,0x83,0x9C, + 0x67,0xB0,0x3F,0xD4,0x3D,0x3A,0x60,0x07,0x81,0xD5,0x99,0xEB,0x40,0xD4,0x1B,0x33, + 0xF0,0xA3,0xE5,0x69,0x06,0x41,0x90,0x8B,0x75,0xA0,0x4E,0xD6,0x29,0x4E,0x49,0xCE, + 0x80,0xAB,0x81,0x25,0x03,0x06,0xBE,0xD4,0x3C,0xDD,0xD0,0x60,0x9D,0xD4,0x3C,0xA8, + 0xA5,0xBC,0x28,0x89,0x8D,0x81,0x13,0x20,0x80,0x72,0x13,0x2B,0x74,0x13,0xD3,0x53, + 0x6D,0x0D,0x00,0x02,0x88,0x81,0x05,0x94,0xFB,0x19,0xF8,0x40,0x49,0x24,0x07,0xC4, + 0xB4,0xB2,0x04,0x66,0x3A,0x06,0xB6,0x5C,0x60,0xA9,0x93,0x9F,0xC2,0xC0,0xEC,0xEE, + 0x1A,0xC2,0xC0,0x56,0x0C,0xD4,0x9B,0x9B,0x0A,0x54,0x5A,0x52,0x52,0xC0,0xC0,0x0C, + 0x0A,0x10,0x46,0x80,0x00,0xD2,0x07,0x08,0x20,0x06,0x2E,0x44,0x2E,0x66,0x48,0xF3, + 0xCD,0xAF,0xCA,0xCC,0xC9,0x49,0xD4,0x37,0xD5,0x33,0x50,0xD0,0x88,0x30,0x34,0xB4, + 0x56,0xF0,0xC9,0xCC,0x2B,0xAD,0x50,0xC8,0x34,0xB3,0x30,0xD3,0x54,0x70,0x04,0x06, + 0x49,0x6A,0x78,0x6A,0x92,0x77,0x66,0x89,0xBE,0xA9,0xB1,0xB9,0x9E,0xA1,0xA1,0x82, + 0x86,0xB7,0x47,0x88,0xAF,0x8F,0x8E,0x42,0x4E,0x66,0x76,0xAA,0x82,0x7B,0x6A,0x72, + 0x76,0xBE,0xA6,0x82,0x73,0x06,0xB0,0x30,0x4A,0xD5,0x37,0x32,0xD6,0x33,0xD0,0x33, + 0x34,0x32,0x37,0xD4,0xB3,0x34,0x57,0x08,0x4E,0x4C,0x4B,0x2C,0xCA,0x84,0xEA,0x62, + 0x60,0x87,0xC6,0x09,0x03,0x07,0x2C,0xAA,0x00,0x00,0x00,0x00,0xFF,0xFF +}; +unsigned char c2s_SYN_STREAM2[] = +{ + 0x80,0x02,0x00,0x01,0x01,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x80,0x00,0x62,0xE0,0x82,0xC7,0x0C,0x33,0x30,0x8C,0x07,0x26,0x74,0xC9,0x0B,0x43, + 0x1E,0x80,0x00,0xD2,0x4F,0x4B,0x2C,0xCB,0x4C,0xCE,0xCF,0xD3,0xCB,0x4C,0xCE,0x07, + 0x08,0xA0,0x41,0x12,0x9C,0x00,0x00,0x00,0x00,0xFF,0xFF +}; +unsigned char c2s_SYN_STREAM3[] = +{ + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x01,0x26,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x38,0xEA,0xDF,0xA2,0x51,0xB2,0x62,0xE0,0x66,0x60,0x83,0xA4,0x17,0x06, + 0x7B,0xB8,0x0B,0x75,0x30,0x2C,0xD6,0xAE,0x40,0x17,0xCD,0xCD,0xB1,0x2E,0xB4,0x35, + 0xD0,0xB3,0xD4,0xD1,0xD2,0xD7,0x02,0xB3,0x2C,0x18,0xF8,0x50,0x73,0x2C,0x83,0x9C, + 0x67,0xB0,0x3F,0xD4,0x3D,0x3A,0x60,0x07,0x81,0xD5,0x99,0xEB,0x40,0xD4,0x1B,0x33, + 0xF0,0xA3,0xE5,0x69,0x06,0x41,0x90,0x8B,0x75,0xA0,0x4E,0xD6,0x29,0x4E,0x49,0xCE, + 0x80,0xAB,0x81,0x25,0x03,0x06,0xBE,0xD4,0x3C,0xDD,0xD0,0x60,0x9D,0xD4,0x3C,0xA8, + 0xA5,0xBC,0x28,0x89,0x8D,0x81,0x13,0x20,0x80,0x72,0x13,0x2B,0x74,0x13,0xD3,0x53, + 0x6D,0x0D,0x00,0x02,0x88,0x81,0x05,0x94,0xFB,0x19,0xF8,0x40,0x49,0x24,0x07,0xC4, + 0xB4,0xB2,0x04,0x66,0x3A,0x06,0xB6,0x5C,0x60,0xA9,0x93,0x9F,0xC2,0xC0,0xEC,0xEE, + 0x1A,0xC2,0xC0,0x56,0x0C,0xD4,0x9B,0x9B,0x0A,0x54,0x5A,0x52,0x52,0xC0,0xC0,0x0C, + 0x0A,0x10,0x46,0x80,0x00,0xD2,0x07,0x08,0x20,0x06,0x2E,0x44,0x2E,0x66,0x48,0xF3, + 0xCD,0xAF,0xCA,0xCC,0xC9,0x49,0xD4,0x37,0xD5,0x33,0x50,0xD0,0x88,0x30,0x34,0xB4, + 0x56,0xF0,0xC9,0xCC,0x2B,0xAD,0x50,0xC8,0x34,0xB3,0x30,0xD3,0x54,0x70,0x04,0x06, + 0x49,0x6A,0x78,0x6A,0x92,0x77,0x66,0x89,0xBE,0xA9,0xB1,0xB9,0x9E,0xA1,0xA1,0x82, + 0x86,0xB7,0x47,0x88,0xAF,0x8F,0x8E,0x42,0x4E,0x66,0x76,0xAA,0x82,0x7B,0x6A,0x72, + 0x76,0xBE,0xA6,0x82,0x73,0x06,0xB0,0x30,0x4A,0xD5,0x37,0x32,0xD6,0x33,0xD0,0x33, + 0x34,0x32,0x37,0xD4,0xB3,0x34,0x57,0x08,0x4E,0x4C,0x4B,0x2C,0xCA,0x84,0xEA,0x62, + 0x60,0x87,0xC6,0x09,0x03,0x07,0x2C,0xAA,0x00,0x00,0x00,0x00,0xFF,0xFF, + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x80,0x00,0x62,0xE0,0x82,0xC7,0x0C,0x33,0x30,0x8C,0x07,0x26,0x74,0xC9,0x0B,0x43, + 0x1E,0x80,0x00,0xD2,0x4F,0x4B,0x2C,0xCB,0x4C,0xCE,0xCF,0xD3,0xCB,0x4C,0xCE,0x07, + 0x08,0xA0,0x41,0x12,0x9C,0x00,0x00,0x00,0x00,0xFF,0xFF +}; +unsigned char c2s_SYN_STREAM4[] = +{ + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00, + 0x80,0x00,0x62,0xE0,0x82,0xC7,0x0C,0x33,0x30,0x8C,0x07,0x26,0x74,0xC9,0x0B,0x43, + 0x1E,0x80,0x00,0xD2,0x4F,0x4B,0x2C,0xCB,0x4C,0xCE,0xCF,0xD3,0xCB,0x4C,0xCE,0x07, + 0x08,0xA0,0x41,0x12,0x9C,0x00,0x00,0x00,0x00,0xFF,0xFF , + 0x80, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xe8, + 0x80,0x02,0x00,0x01,0x01,0x00,0x01,0x26,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x38,0xEA,0xDF,0xA2,0x51,0xB2,0x62,0xE0,0x66,0x60,0x83,0xA4,0x17,0x06, + 0x7B,0xB8,0x0B,0x75,0x30,0x2C,0xD6,0xAE,0x40,0x17,0xCD,0xCD,0xB1,0x2E,0xB4,0x35, + 0xD0,0xB3,0xD4,0xD1,0xD2,0xD7,0x02,0xB3,0x2C,0x18,0xF8,0x50,0x73,0x2C,0x83,0x9C, + 0x67,0xB0,0x3F,0xD4,0x3D,0x3A,0x60,0x07,0x81,0xD5,0x99,0xEB,0x40,0xD4,0x1B,0x33, + 0xF0,0xA3,0xE5,0x69,0x06,0x41,0x90,0x8B,0x75,0xA0,0x4E,0xD6,0x29,0x4E,0x49,0xCE, + 0x80,0xAB,0x81,0x25,0x03,0x06,0xBE,0xD4,0x3C,0xDD,0xD0,0x60,0x9D,0xD4,0x3C,0xA8, + 0xA5,0xBC,0x28,0x89,0x8D,0x81,0x13,0x20,0x80,0x72,0x13,0x2B,0x74,0x13,0xD3,0x53, + 0x6D,0x0D,0x00,0x02,0x88,0x81,0x05,0x94,0xFB,0x19,0xF8,0x40,0x49,0x24,0x07,0xC4, + 0xB4,0xB2,0x04,0x66,0x3A,0x06,0xB6,0x5C,0x60,0xA9,0x93,0x9F,0xC2,0xC0,0xEC,0xEE, + 0x1A,0xC2,0xC0,0x56,0x0C,0xD4,0x9B,0x9B,0x0A,0x54,0x5A,0x52,0x52,0xC0,0xC0,0x0C, + 0x0A,0x10,0x46,0x80,0x00,0xD2,0x07,0x08,0x20,0x06,0x2E,0x44,0x2E,0x66,0x48,0xF3, + 0xCD,0xAF,0xCA,0xCC,0xC9,0x49,0xD4,0x37,0xD5,0x33,0x50,0xD0,0x88,0x30,0x34,0xB4, + 0x56,0xF0,0xC9,0xCC,0x2B,0xAD,0x50,0xC8,0x34,0xB3,0x30,0xD3,0x54,0x70,0x04,0x06, + 0x49,0x6A,0x78,0x6A,0x92,0x77,0x66,0x89,0xBE,0xA9,0xB1,0xB9,0x9E,0xA1,0xA1,0x82, + 0x86,0xB7,0x47,0x88,0xAF,0x8F,0x8E,0x42,0x4E,0x66,0x76,0xAA,0x82,0x7B,0x6A,0x72, + 0x76,0xBE,0xA6,0x82,0x73,0x06,0xB0,0x30,0x4A,0xD5,0x37,0x32,0xD6,0x33,0xD0,0x33, + 0x34,0x32,0x37,0xD4,0xB3,0x34,0x57,0x08,0x4E,0x4C,0x4B,0x2C,0xCA,0x84,0xEA,0x62, + 0x60,0x87,0xC6,0x09,0x03,0x07,0x2C,0xAA,0x00,0x00,0x00,0x00,0xFF,0xFF + +}; +TEST(spdyzlibfilter_test) +{ +// SpdyConnection MySpdyConn(NULL, NULL, 2); +// MySpdyConn.onReadEx(c2s_SYN_STREAM3, sizeof(c2s_SYN_STREAM3)); + + AutoBuf Result; + int ntotal = 0; +// char Result.begin()[2000]; + char pData[2000]; + LoopBuf Result1(10); + + Result1.clear(); + int lpbuffSize = Result1.available(); + //int lpbuffSizeC = Result1.contiguous(); + Result1.append( pData, lpbuffSize -8); + //int lpbuffSize1 = Result1.available(); + //int lpbuffSizeC1 = Result1.contiguous(); + int DataSize = Result1.size(); + char* pResult1 = Result1.end(); + printf("This is spdyzlibfilter_test!\n"); + SpdyZlibFilter TestInflator; + SpdyZlibFilter TestInflator1; + SpdyZlibFilter TestDeflator; + TestInflator.init( 1, 1 ); + TestInflator1.init( 1, 1 ); + TestDeflator.init( 0, 1 ); + Result.clear(); + int n = TestInflator.spdyHeaderInflate((char*)c2s_SYN_STREAM1+18, sizeof(c2s_SYN_STREAM1)-18, Result); + CHECK( n > 0 ); + printbuff( (unsigned char*)Result.begin(), n); + printheader( (unsigned char*)Result.begin(), n); + int n1 = TestDeflator.spdyHeaderDeflate(Result.begin(), 50, &Result1, 0); + CHECK( n1 >= 0 ); + ntotal += n1; + printf("finished Compressing 0-50 n1=%d, total=%d\n", n1, ntotal); + n1 = TestDeflator.spdyHeaderDeflate(Result.begin() + 50, 200, &Result1, 0); + CHECK( n1 >= 0 ); + ntotal += n1; + printf("finished Compressing 50-250 n1=%d, total=%d\n", n1, ntotal); + n1 = TestDeflator.spdyHeaderDeflate(Result.begin() + 250, n-250, &Result1, Z_SYNC_FLUSH); + CHECK( n1 >= 0 ); + ntotal += n1; + printf("finished Compressing 250-%d n1=%d, total=%d\n", n, n1, ntotal); + printf("UncompressLen=%d, middle=%d, CompressedLen=%d\n", n, n1, ntotal); + Result.clear(); + pResult1 = Result1.getPointer(DataSize); + n = TestInflator1.spdyHeaderInflate(pResult1, ntotal, Result); + CHECK( n > 0 ); + printbuff( (unsigned char*)Result.begin(), n); + printheader( (unsigned char*)Result.begin(), n); + Result.clear(); + n = TestInflator.spdyHeaderInflate((char*)c2s_SYN_STREAM2+18, sizeof(c2s_SYN_STREAM2)-18, Result); + CHECK( n > 0 ); + printbuff( (unsigned char*)Result.begin(), n); + printheader( (unsigned char*)Result.begin(), n); + Result1.clear(); + n1 = TestDeflator.spdyHeaderDeflate(Result.begin(), n, &Result1, Z_SYNC_FLUSH); + CHECK( n1 > 0 ); + printf("UncompressLen=%d, CompressedLen=%d\n", n, n1); + Result.clear(); + pResult1 = Result1.getPointer(0); + n = TestInflator1.spdyHeaderInflate(pResult1, n1, Result); + CHECK( n > 0 ); + printbuff( (unsigned char*)Result.begin(), n); + printheader( (unsigned char*)Result.begin(), n); +} + + +#endif \ No newline at end of file diff --git a/src/test/util/CMakeLists.txt b/src/test/util/CMakeLists.txt index b93996af7..1735c7e5b 100644 --- a/src/test/util/CMakeLists.txt +++ b/src/test/util/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8) ########### next target ############### SET(util_STAT_SRCS + httpfetchtest.cpp pcregextest.cpp ghashtest.cpp linkedobjtest.cpp @@ -37,9 +38,9 @@ add_library(testutil STATIC ${util_STAT_SRCS}) # #libutil_a_METASOURCES = AUTO # -#libutil_a_SOURCES = pcregextest.cpp ghashtest.cpp linkedobjtest.cpp gzipbuftest.cpp vmembuftest.cpp gpathtest.cpp gstringtest.cpp poolalloctest.cpp xmlnodetest.cpp accesscontroltest.cpp loopbuftest.cpp base64test.cpp logfiletest.cpp stringmaptest.cpp +#libutil_a_SOURCES = httpfetchtest.cpp pcregextest.cpp ghashtest.cpp linkedobjtest.cpp gzipbuftest.cpp vmembuftest.cpp gpathtest.cpp gstringtest.cpp poolalloctest.cpp xmlnodetest.cpp accesscontroltest.cpp loopbuftest.cpp base64test.cpp logfiletest.cpp stringmaptest.cpp # # -#EXTRA_DIST = stringmaptest.cpp stringmaptest.h logfiletest.cpp logfiletest.h base64test.cpp base64test.h loopbuftest.h loopbuftest.cpp accesscontroltest.h accesscontroltest.cpp xmlnodetest.cpp xmlnodetest.h poolalloctest.cpp poolalloctest.h gstringtest.cpp gstringtest.h gpathtest.h gpathtest.cpp vmembuftest.cpp vmembuftest.h gzipbuftest.cpp gzipbuftest.h linkedobjtest.cpp linkedobjtest.h ghashtest.cpp ghashtest.h pcregextest.cpp pcregextest.h +#EXTRA_DIST = stringmaptest.cpp stringmaptest.h logfiletest.cpp logfiletest.h base64test.cpp base64test.h loopbuftest.h loopbuftest.cpp accesscontroltest.h accesscontroltest.cpp xmlnodetest.cpp xmlnodetest.h poolalloctest.cpp poolalloctest.h gstringtest.cpp gstringtest.h gpathtest.h gpathtest.cpp vmembuftest.cpp vmembuftest.h gzipbuftest.cpp gzipbuftest.h linkedobjtest.cpp linkedobjtest.h ghashtest.cpp ghashtest.h pcregextest.cpp pcregextest.h httpfetchtest.cpp httpfetchtest.h # ######## kdevelop will overwrite this part!!! (end)############ diff --git a/src/test/util/base64test.cpp b/src/test/util/base64test.cpp index faf22b6e4..e6dd040bc 100644 --- a/src/test/util/base64test.cpp +++ b/src/test/util/base64test.cpp @@ -20,6 +20,7 @@ #include "base64test.h" #include +#include #include #include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" @@ -30,6 +31,17 @@ TEST( Base64Test_test) const char * pResult = "Aladdin:open sesame"; CHECK( -1 != Base64::decode( pEncoded, 50, achDecoded ) ); CHECK( 0 == strcmp( pResult, achDecoded ) ); + + const char *pDecoded = "Aladdin:open sesame"; + char achEncoded[50]; + unsigned int len = Base64::encode(pDecoded, strlen(pDecoded), achEncoded); + achEncoded[len] = 0; + printf("%s\n", achEncoded); + + CHECK (len == strlen(pEncoded)); + CHECK (0 == memcmp(achEncoded, pEncoded, len)); + + } #endif diff --git a/src/test/util/gpathtest.cpp b/src/test/util/gpathtest.cpp index e97a78fb3..01c71a629 100644 --- a/src/test/util/gpathtest.cpp +++ b/src/test/util/gpathtest.cpp @@ -29,7 +29,6 @@ TEST(GPathTest_test) { char buf[256]; - int n; char * pBufEnd = &buf[256]; strcpy(buf, "/b/./"); CHECK(GPath::clean(buf)==0); @@ -81,7 +80,7 @@ TEST(GPathTest_test) strcpy( buf, curPath); strcat( buf, "/serverroot/wwwroot/index.html" ); - n = GPath::checkSymLinks( buf, buf + strlen( buf ), pBufEnd, buf, 0 ); + GPath::checkSymLinks( buf, buf + strlen( buf ), pBufEnd, buf, 0 ); // CHECK( n == -1 ); // char * p = getcwd( buf, 256 ); diff --git a/src/test/util/httpfetchtest.cpp b/src/test/util/httpfetchtest.cpp new file mode 100644 index 000000000..2a98b15f3 --- /dev/null +++ b/src/test/util/httpfetchtest.cpp @@ -0,0 +1,110 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifdef RUN_TEST + +#include +#include +#include +#include +#include "socket/gsockaddr.h" +#include "test/unittest-cpp/UnitTest++/src/UnitTest++.h" + +//TEST(httpfetchTest_Test) +void VOID_TEST()//httpfetchTest_Test) +{ + printf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + printf ("THIS TEST CAN ONLY TEST BY DEBUG with breakpoints\n"); + printf ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + + void *p = NULL; + HttpFetch *pHttpFetch = new HttpFetch; + pHttpFetch->setCallBack(NULL, p); + //pHttpFetch->setTimeout(100); + + int nonblock = 0; + const char * pBody = NULL; + int bodyLen = 0; + const char * pSaveFile = "./lswslogo3.png"; + + + pHttpFetch->setProxyServerAddr("127.0.0.1:8000"); + int ret = pHttpFetch->startReq( "http://www.litespeedtech.com/templates/litespeed/images/lswslogo3.png", + nonblock, 1, + pBody, + bodyLen, + pSaveFile); + delete pHttpFetch; + pHttpFetch = NULL; + + pHttpFetch = new HttpFetch; + ret = pHttpFetch->startReq( "http://www.litespeedtech.com/templates/litespeed/images/lswslogo3.png", + nonblock, 1, + pBody, + bodyLen, + pSaveFile, NULL, "www.litespeedtech.com:80"); + delete pHttpFetch; + pHttpFetch = NULL; + + pHttpFetch = new HttpFetch; + GSockAddr gsock; + gsock.setHttpUrl("http://www.litespeedtech.com/", strlen("http://www.litespeedtech.com/")); + + GSockAddr gsock1; + gsock1.setHttpUrl("https://www.litespeedtech.com/", strlen("https://www.litespeedtech.com/")); + + GSockAddr gsock2; + gsock2.setHttpUrl("http://www.litespeedtech.com:888", strlen("http://www.litespeedtech.com:998")); + + GSockAddr gsock3; + gsock3.setHttpUrl("https://www.litespeedtech.com:444", strlen("https://www.litespeedtech.com:998")); + + GSockAddr gsock4; + gsock4.setHttpUrl("http://www.litespeedtech.com/dfgfdgfdgfdg", strlen("http://www.litespeedtech.com/dfgfdgfdgfdg")); + + GSockAddr gsock5; + gsock5.setHttpUrl("http://www.litespeedtech.com:888/dfgfdgfdgfdg", strlen("http://www.litespeedtech.com:888/dfgfdgfdgfdg")); + + GSockAddr gsock6; + gsock6.setHttpUrl("https://www.litespeedtech.com/dfgfdgfdgfdg", strlen("https://www.litespeedtech.com/dfgfdgfdgfdg")); + + GSockAddr gsock7; + gsock7.setHttpUrl("https://www.litespeedtech.com:444/dfgfdgfdgfdg", strlen("https://www.litespeedtech.com:888/dfgfdgfdgfdg")); + + ret = pHttpFetch->startReq( "http://www.litespeedtech.com/templates/litespeed/images/lswslogo3.png", + nonblock, 1, + pBody, + bodyLen, + pSaveFile, 0, gsock); + delete pHttpFetch; + pHttpFetch = NULL; + + pHttpFetch = new HttpFetch; + pHttpFetch->setProxyServerAddr("127.0.0.1:8000"); + ret = pHttpFetch->startReq( "http://www.litespeedtech.com/templates/litespeed/images/lswslogo3.png", + nonblock, 1, + pBody, + bodyLen, + pSaveFile, 0, gsock); + delete pHttpFetch; + pHttpFetch = NULL; + + CHECK(ret == 0); + +} + +#endif diff --git a/src/test/util/httpfetchtest.h b/src/test/util/httpfetchtest.h new file mode 100644 index 000000000..841571fe7 --- /dev/null +++ b/src/test/util/httpfetchtest.h @@ -0,0 +1,27 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifdef RUN_TEST + +#ifndef HTTPFTECHTEST_H +#define HTTPFTECHTEST_H + + + +#endif + +#endif diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a386fc2e7..51c5eb982 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(sysinfo) ########### next target ############### SET(util_STAT_SRCS + httpfetchdriver.cpp httpfetch.cpp ni_fio.c linkobjpool.cpp @@ -82,6 +83,7 @@ add_library(util STATIC ${util_STAT_SRCS}) # #SUBDIRS = stl misc sysinfo # -#EXTRA_DIST = daemonize.cpp daemonize.h pcutil.cpp pcutil.h base64.cpp base64.h tsingleton.cpp tsingleton.h stringtool.cpp stringtool.h loopbuf.cpp loopbuf.h signalutil.cpp signalutil.h accesscontrol.cpp accesscontrol.h iovec.cpp iovec.h xmlnode.cpp xmlnode.h env.cpp env.h poolalloc.cpp poolalloc.h gstring.cpp gstring.h logtracker.cpp logtracker.h gpath.h gpath.cpp objpool.cpp objpool.h linkedobj.cpp linkedobj.h ienv.h gpointerlist.cpp gpointerlist.h refcounter.cpp refcounter.h semaphore.cpp semaphore.h stringlist.cpp stringlist.h blockbuf.cpp blockbuf.h vmembuf.cpp vmembuf.h gzipbuf.cpp gzipbuf.h connpool.cpp connpool.h dlinkqueue.cpp dlinkqueue.h iconnection.cpp iconnection.h crashguard.cpp crashguard.h guardedapp.cpp guardedapp.h emailsender.cpp emailsender.h ghash.cpp ghash.h hashstringmap.cpp hashstringmap.h pool.cpp pool.h swap.h staticobj.cpp staticobj.h autostr.cpp autostr.h pcregex.cpp pcregex.h fdpass.cpp fdpass.h gfactory.cpp gfactory.h duplicable.cpp duplicable.h rlimits.cpp rlimits.h mysleep.h mysleep.c tlinklist.cpp tlinklist.h keydata.cpp keydata.h hashdatacache.cpp hashdatacache.h pidfile.cpp pidfile.h linkobjpool.cpp linkobjpool.h accessdef.h ni_fio.h ni_fio.c httpfetch.cpp httpfetch.h +#EXTRA_DIST = daemonize.cpp daemonize.h pcutil.cpp pcutil.h base64.cpp base64.h tsingleton.cpp tsingleton.h stringtool.cpp stringtool.h loopbuf.cpp loopbuf.h signalutil.cpp signalutil.h accesscontrol.cpp accesscontrol.h iovec.cpp iovec.h xmlnode.cpp xmlnode.h env.cpp env.h poolalloc.cpp poolalloc.h gstring.cpp gstring.h logtracker.cpp logtracker.h gpath.h gpath.cpp objpool.cpp objpool.h linkedobj.cpp linkedobj.h ienv.h gpointerlist.cpp gpointerlist.h refcounter.cpp refcounter.h semaphore.cpp semaphore.h stringlist.cpp stringlist.h blockbuf.cpp blockbuf.h vmembuf.cpp vmembuf.h gzipbuf.cpp gzipbuf.h connpool.cpp connpool.h dlinkqueue.cpp dlinkqueue.h iconnection.cpp iconnection.h crashguard.cpp crashguard.h guardedapp.cpp guardedapp.h emailsender.cpp emailsender.h ghash.cpp ghash.h hashstringmap.cpp hashstringmap.h pool.cpp pool.h swap.h staticobj.cpp staticobj.h autostr.cpp autostr.h pcregex.cpp pcregex.h fdpass.cpp fdpass.h gfactory.cpp gfactory.h duplicable.cpp duplicable.h rlimits.cpp rlimits.h mysleep.h +# mysleep.c tlinklist.cpp tlinklist.h keydata.cpp keydata.h hashdatacache.cpp hashdatacache.h pidfile.cpp pidfile.h linkobjpool.cpp linkobjpool.h accessdef.h ni_fio.h ni_fio.c httpfetch.cpp httpfetch.h # ######## kdevelop will overwrite this part!!! (end)############ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 92db4732e..7e9fe428b 100755 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -4,7 +4,7 @@ noinst_LIBRARIES = libutil.a INCLUDES = -I$(top_srcdir)/src libutil_a_METASOURCES = AUTO -libutil_a_SOURCES = httpfetch.cpp ni_fio.c linkobjpool.cpp pidfile.cpp \ +libutil_a_SOURCES = httpfetch.cpp httpfetchdriver.cpp ni_fio.c linkobjpool.cpp pidfile.cpp \ hashdatacache.cpp keydata.cpp tlinklist.cpp rlimits.cpp duplicable.cpp gfactory.cpp fdpass.cpp \ pcregex.cpp autostr.cpp staticobj.cpp pool.cpp hashstringmap.cpp \ ghash.cpp emailsender.cpp guardedapp.cpp crashguard.cpp \ diff --git a/src/util/Makefile.in b/src/util/Makefile.in index c630fc9bb..9b03af07f 100644 --- a/src/util/Makefile.in +++ b/src/util/Makefile.in @@ -67,8 +67,8 @@ AR = ar ARFLAGS = cru libutil_a_AR = $(AR) $(ARFLAGS) libutil_a_LIBADD = -am_libutil_a_OBJECTS = httpfetch.$(OBJEXT) ni_fio.$(OBJEXT) \ - linkobjpool.$(OBJEXT) pidfile.$(OBJEXT) \ +am_libutil_a_OBJECTS = httpfetch.$(OBJEXT) httpfetchdriver.$(OBJEXT) \ + ni_fio.$(OBJEXT) linkobjpool.$(OBJEXT) pidfile.$(OBJEXT) \ hashdatacache.$(OBJEXT) keydata.$(OBJEXT) tlinklist.$(OBJEXT) \ rlimits.$(OBJEXT) duplicable.$(OBJEXT) gfactory.$(OBJEXT) \ fdpass.$(OBJEXT) pcregex.$(OBJEXT) autostr.$(OBJEXT) \ @@ -223,7 +223,7 @@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libutil.a INCLUDES = -I$(top_srcdir)/src libutil_a_METASOURCES = AUTO -libutil_a_SOURCES = httpfetch.cpp ni_fio.c linkobjpool.cpp pidfile.cpp \ +libutil_a_SOURCES = httpfetch.cpp httpfetchdriver.cpp ni_fio.c linkobjpool.cpp pidfile.cpp \ hashdatacache.cpp keydata.cpp tlinklist.cpp rlimits.cpp duplicable.cpp gfactory.cpp fdpass.cpp \ pcregex.cpp autostr.cpp staticobj.cpp pool.cpp hashstringmap.cpp \ ghash.cpp emailsender.cpp guardedapp.cpp crashguard.cpp \ @@ -306,6 +306,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashdatacache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashstringmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpfetch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpfetchdriver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iconnection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iovec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keydata.Po@am__quote@ diff --git a/src/util/accesscontrol.cpp b/src/util/accesscontrol.cpp index 21642b42f..88c755561 100644 --- a/src/util/accesscontrol.cpp +++ b/src/util/accesscontrol.cpp @@ -532,7 +532,6 @@ int AccessControl::insSubNetControl( in_addr_t subNet, int allowed ) { SubNetNode* pCur = m_pRoot; - SubNetNode* pNext; /* while ( ( pNext = pCur->matchNode( subNet ) ) != NULL ) { @@ -549,7 +548,7 @@ int AccessControl::insSubNetControl( in_addr_t subNet, return 0; } -static char s_maskbits[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; +static unsigned char s_maskbits[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; int AccessControl::parseNetmask( const char * netMask, int maxbits, void *pMask ) { char * pEnd; diff --git a/src/util/autobuf.h b/src/util/autobuf.h index 64e369874..43df78f01 100644 --- a/src/util/autobuf.h +++ b/src/util/autobuf.h @@ -37,13 +37,10 @@ class AutoBuf ~AutoBuf(); int available() const { return m_pBufEnd - m_pEnd; } - char * begin() { return m_pBuf; } - char * end() { return m_pEnd; } - const char * begin() const { return m_pBuf; } - const char * end() const { return m_pEnd; } + char * begin() const { return m_pBuf; } + char * end() const { return m_pEnd; } - char * getPointer( int offset ) { return m_pBuf + offset; } - const char * getPointer( int offset ) const { return m_pBuf + offset; } + char * getPointer( int offset ) const { return m_pBuf + offset; } void used( int size ) { m_pEnd += size; } void clear() { m_pEnd = m_pBuf; } @@ -51,11 +48,6 @@ class AutoBuf int capacity() const { return m_pBufEnd - m_pBuf; } int size() const { return m_pEnd - m_pBuf; } - char * inc( char * &pCh ) const - { return ++pCh; } - const char* inc( const char * &pCh) const - { return ++pCh; } - int reserve( int size ) { return allocate( size ); } void resize( int size ) { m_pEnd = m_pBuf + size; } diff --git a/src/util/autostr.cpp b/src/util/autostr.cpp index f8ae098ca..3f639097c 100644 --- a/src/util/autostr.cpp +++ b/src/util/autostr.cpp @@ -87,4 +87,12 @@ AutoStr2::AutoStr2( const AutoStr2 & rhs) int AutoStr2::setStr( const char * pStr ) { return setStr( pStr, strlen( pStr ) ); } +void AutoStr2::append( const char * str, const int len ) +{ + m_iStrLen += len; + char *p = resizeBuf(m_iStrLen + 1); + memcpy(p + m_iStrLen - len, str, len ); + *(p + m_iStrLen) = 0; +} + diff --git a/src/util/autostr.h b/src/util/autostr.h index e52bc0a1b..dcb2820a6 100644 --- a/src/util/autostr.h +++ b/src/util/autostr.h @@ -78,6 +78,7 @@ class AutoStr2 : public AutoStr int setStr( const char * pStr ); int setStr( const char * pStr, int len ) { m_iStrLen = len; return AutoStr::setStr( pStr, len ); } + void append( const char * str, const int len ); }; static inline int operator==( const AutoStr& s1, const char * s2 ) diff --git a/src/util/base64.cpp b/src/util/base64.cpp index a67e35ec6..dbdd1a042 100644 --- a/src/util/base64.cpp +++ b/src/util/base64.cpp @@ -17,7 +17,7 @@ *****************************************************************************/ #include -const unsigned char Base64::s_decodeTable[128] = +static const unsigned char s_decodeTable[128] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 00-0F */ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 10-1F */ @@ -29,12 +29,9 @@ const unsigned char Base64::s_decodeTable[128] = 41,42,43,44,45,46,47,48,49,50,51,255,255,255,255,255 /* 70-7F */ }; - -Base64::Base64(){ -} -Base64::~Base64(){ -} - +static const unsigned char s_encodeTable[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int Base64::decode( const char * encoded, int size, char * decoded ) { register const char * pEncoded = encoded; @@ -74,4 +71,42 @@ int Base64::decode( const char * encoded, int size, char * decoded ) return pDecoded - (unsigned char *)decoded; } +int Base64::encode( const char *decoded, int size, char * encoded ) +{ + register const unsigned char * pDecoded = (const unsigned char *)decoded; + register const unsigned char * pEnd = (const unsigned char *)decoded + size ; + register char * pEncoded = encoded; + register unsigned char ch; + + size %= 3; + pEnd -= size; + + while ( pEnd > pDecoded ) + { + *pEncoded++ = s_encodeTable[( ( ch = *pDecoded++ ) >> 2 ) & 0x3f]; + *pEncoded++ = s_encodeTable[(( ch & 0x03 ) << 4 ) | ( *pDecoded >> 4 )]; + ch = *pDecoded++; + *pEncoded++ = s_encodeTable[(( ch & 0x0f ) << 2 ) | ( *pDecoded >> 6 )]; + *pEncoded++ = s_encodeTable[ *pDecoded++ & 0x3f]; + } + if ( size > 0 ) + { + *pEncoded++ = s_encodeTable[( (ch = *pDecoded++) >> 2 ) & 0x3f]; + + if (size == 1) + { + *pEncoded++ = s_encodeTable[( ch & 0x03 ) << 4]; + *pEncoded++ = '='; + + } + else + { + *pEncoded++ = s_encodeTable[(( ch & 0x03 ) << 4) | ( *pDecoded >> 4 )]; + *pEncoded++ = s_encodeTable[( *pDecoded & 0x0f ) << 2]; + } + *pEncoded++ = '='; + } + + return pEncoded - encoded; +} diff --git a/src/util/base64.h b/src/util/base64.h index 8b32b4543..f0861d8f4 100644 --- a/src/util/base64.h +++ b/src/util/base64.h @@ -19,15 +19,14 @@ #define BASE64_H - class Base64 { public: - static const unsigned char s_decodeTable[128]; - Base64(); - ~Base64(); + Base64() {}; + ~Base64() {}; static int decode( const char * encoded, int encodeLen, char * decoded ); - + static int encode( const char *decoded, int decodedLen, char * encoded ); + static int encode_length(int len) { return (((len + 2) / 3) * 4); }; }; #endif diff --git a/src/util/fdpass.cpp b/src/util/fdpass.cpp index 2db4fd1f0..56f4faa00 100644 --- a/src/util/fdpass.cpp +++ b/src/util/fdpass.cpp @@ -165,7 +165,7 @@ int test_fdpass() close( fd ); int n = 0; int fd1; - int ret = FDPass::read_fd( intercommfds[0], &n, sizeof( int ), &fd1 ); + FDPass::read_fd( intercommfds[0], &n, sizeof( int ), &fd1 ); printf( "recv fd: %d, n: %d\n", fd1, n ); if ( fd1 != -1 ) return 0; diff --git a/src/util/gpointerlist.h b/src/util/gpointerlist.h index c22b6b535..8e61bdcfb 100644 --- a/src/util/gpointerlist.h +++ b/src/util/gpointerlist.h @@ -23,6 +23,7 @@ #include #include +#include typedef int (*gpl_for_each_fn)( void *); @@ -41,7 +42,7 @@ class GPointerList GPointerList(); explicit GPointerList( size_t initSize ); ~GPointerList(); - size_t size() const { return m_pEnd - m_pStore; } + ssize_t size() const { return m_pEnd - m_pStore; } bool empty() const { return m_pEnd == m_pStore; } bool full() const { return m_pEnd == m_pStoreEnd; } size_t capacity() const { return m_pStoreEnd - m_pStore; } diff --git a/src/util/httpfetch.cpp b/src/util/httpfetch.cpp index 97762de40..a5c306d11 100644 --- a/src/util/httpfetch.cpp +++ b/src/util/httpfetch.cpp @@ -16,10 +16,11 @@ * along with this program. If not, see http://www.gnu.org/licenses/. * *****************************************************************************/ #include "httpfetch.h" - #include +#include #include #include +#include #include #include @@ -29,7 +30,8 @@ #include #include #include -#include + +static int HttpFetchCounter = 0; HttpFetch::HttpFetch() : m_fdHttp( -1 ) @@ -43,23 +45,35 @@ HttpFetch::HttpFetch() , m_reqBodyLen( 0 ) , m_connTimeout( 20 ) , m_pRespContentType( NULL ) + , m_psProxyServerAddr( NULL ) , m_pProxyServerAddr( NULL ) , m_callback( NULL ) + , m_pHttpFetchDriver( NULL ) + , m_iTimeoutSec ( -1 ) + , m_iReqInited ( 0 ) + , m_iEnableDebug( 0 ) { + m_pLogger = Logger::getRootLogger(); + m_iLoggerId = HttpFetchCounter ++; + //m_pLogger->debug( "HttpFetch[%d]::HttpFetch()", getLoggerId() ); } HttpFetch::~HttpFetch() { - if ( m_fdHttp != -1 ) - close( m_fdHttp ); + stopDriver(); + closeConnection(); if ( m_pBuf ) delete m_pBuf; if ( m_pReqBuf ) free( m_pReqBuf ); if ( m_pRespContentType ) free( m_pRespContentType ); + if (m_psProxyServerAddr) + free( m_psProxyServerAddr ); if ( m_pProxyServerAddr ) - free( m_pProxyServerAddr ); + delete m_pProxyServerAddr; + if ( m_pHttpFetchDriver ) + delete m_pHttpFetchDriver; } void HttpFetch::releaseResult() @@ -95,6 +109,7 @@ void HttpFetch::reset() m_reqSent = 0; m_reqHeaderLen = 0; m_reqBodyLen = 0; + m_iReqInited = 0; } int HttpFetch::allocateBuf( const char * pSaveFile ) @@ -108,19 +123,27 @@ int HttpFetch::allocateBuf( const char * pSaveFile ) if ( !m_pBuf ) return -1; if ( pSaveFile ) + { ret = m_pBuf->set( pSaveFile, 8192 ); + if ( ret == 0 && m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::allocateBuf File %s created.", getLoggerId(), pSaveFile ); + } else ret = m_pBuf->set( VMBUF_ANON_MAP, 8192 ); return ret; } -int HttpFetch::startReq( const char * pURL, int nonblock, - const char * pBody, int bodyLen, const char * pSaveFile, - const char * pContentType, const char * addrServer ) +int HttpFetch::intiReq(const char * pURL, const char * pBody, int bodyLen, + const char * pSaveFile, const char * pContentType) { + if (m_iReqInited) + return 0; + m_iReqInited = 1; + if ( m_fdHttp != -1 ) return -1; + m_pReqBody = pBody; if ( m_pReqBody ) { @@ -134,9 +157,50 @@ int HttpFetch::startReq( const char * pURL, int nonblock, if ( buildReq( "GET", pURL ) == -1 ) return -1; } + if ( allocateBuf( pSaveFile ) == -1 ) return -1; - return startProcessReq( nonblock, addrServer ); + + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::intiReq url=%s", getLoggerId(), pURL ); + return 0; +} + +int HttpFetch::startReq( const char * pURL, int nonblock, int enableDriver, + const char * pBody, int bodyLen, const char * pSaveFile, + const char * pContentType, const char * addrServer ) +{ + if ( intiReq(pURL, pBody, bodyLen,pSaveFile, pContentType) != 0) + return -1; + + if ( m_pProxyServerAddr ) + return startReq( pURL, nonblock, enableDriver, pBody, bodyLen, pSaveFile, + pContentType, *m_pProxyServerAddr ); + + GSockAddr server; + if ( addrServer == NULL) + addrServer = m_achHost; + if ( 0 != server.set( addrServer, NO_ANY |DO_NSLOOKUP)) + return -1; + + return startReq( pURL, nonblock, enableDriver, pBody, bodyLen, + pSaveFile, pContentType, server ); +} + +int HttpFetch::startReq( const char * pURL, int nonblock, int enableDriver, + const char * pBody, int bodyLen, const char * pSaveFile, + const char * pContentType, const GSockAddr & sockAddr ) +{ + if ( intiReq(pURL, pBody, bodyLen,pSaveFile, pContentType) != 0) + return -1; + + if (enableDriver) + m_pHttpFetchDriver = new HttpFetchDriver( this ); + + if ( m_pProxyServerAddr ) + return startProcessReq( nonblock, *m_pProxyServerAddr ); + else + return startProcessReq( nonblock, sockAddr ); } int HttpFetch::buildReq( const char * pMethod, const char * pURL, const char * pContentType ) @@ -188,25 +252,24 @@ int HttpFetch::buildReq( const char * pMethod, const char * pURL, const char * p strcat( m_achHost, ":80" ); m_reqHeaderLen += 2; m_reqSent = 0; + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::buildReq Host=%s [0]", getLoggerId(), m_achHost ); return 0; } -int HttpFetch::startProcessReq( int nonblock, const char * pAddr) +int HttpFetch::startProcessReq( int nonblock, const GSockAddr & sockAddr ) { m_reqState = 0; - if ( m_fdHttp != -1 ) - close( m_fdHttp ); - int iFLTag = 0; - iFLTag = O_NONBLOCK; - if ( m_pProxyServerAddr ) - pAddr = m_pProxyServerAddr; - if ( !pAddr ) - pAddr = m_achHost; - int ret = CoreSocket::connect( pAddr, iFLTag, &m_fdHttp, 1 ); + + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::startProcessReq sockAddr=%s", getLoggerId(), sockAddr.toString() ); + int ret = CoreSocket::connect( sockAddr, O_NONBLOCK, &m_fdHttp ); if ( m_fdHttp == -1 ) return -1; ::fcntl( m_fdHttp, F_SETFD, FD_CLOEXEC ); + startDriver(); + if ( !nonblock ) { fd_set readfds; @@ -243,6 +306,9 @@ int HttpFetch::startProcessReq( int nonblock, const char * pAddr) } else m_reqState = 1; //connecting + + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::startProcessReq ret=%d state=%d", getLoggerId(), ret, m_reqState ); return 0; } @@ -278,6 +344,9 @@ int HttpFetch::sendReq() ret = ::nio_write( m_fdHttp, m_pReqBuf + m_reqSent, m_reqHeaderLen - m_reqSent ); //write( 1, m_pReqBuf + m_reqSent, m_reqHeaderLen - m_reqSent ); + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::sendReq::nio_write fd=%d len=%d [%d - %d] ret=%d", getLoggerId(), m_fdHttp, + m_reqHeaderLen - m_reqSent, m_reqHeaderLen, m_reqSent, ret ); if ( ret > 0 ) m_reqSent += ret; else if ( ret == -1 ) @@ -391,17 +460,9 @@ int HttpFetch::recvResp() char achBuf[8192]; while( m_statusCode != -1 ) { - fd_set readfds; - struct timeval timeout; - FD_ZERO( &readfds ); - FD_SET( m_fdHttp, &readfds ); - timeout.tv_sec = m_connTimeout; timeout.tv_usec = 0; - if ((ret = select(m_fdHttp+1, &readfds, &readfds, NULL, &timeout)) != 1 ) - { - endReq( -1 ); - return -1; - } ret = ::nio_read( m_fdHttp, achBuf, 8192 ); + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::recvResp fd=%d ret=%d", getLoggerId(), m_fdHttp, ret ); if ( ret == 0 ) { if ( m_respBodyLen == -1 ) @@ -551,13 +612,45 @@ int HttpFetch::process() void HttpFetch::setProxyServerAddr( const char * pAddr ) { if ( m_pProxyServerAddr ) + delete m_pProxyServerAddr; + + if ( pAddr ) { - free( m_pProxyServerAddr ); - m_pProxyServerAddr = NULL; + m_pProxyServerAddr = new GSockAddr(); + m_pProxyServerAddr->set( pAddr, NO_ANY | DO_NSLOOKUP ); + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::setProxyServerAddr %s", getLoggerId(), pAddr); + if (m_psProxyServerAddr) + free( m_psProxyServerAddr ); + m_psProxyServerAddr = strdup( pAddr ); } - if ( pAddr ) - m_pProxyServerAddr = strdup( pAddr ); } +void HttpFetch::closeConnection() +{ + if ( m_fdHttp != -1 ) + { + if ( m_iEnableDebug ) + m_pLogger->debug( "HttpFetch[%d]::closeConnection fd=%d ", getLoggerId(), m_fdHttp); + close( m_fdHttp ); + m_fdHttp = -1; + } +} +void HttpFetch::startDriver() +{ + if (m_pHttpFetchDriver) + { + m_pHttpFetchDriver->setfd(m_fdHttp); + m_pHttpFetchDriver->start(); + } +} + +void HttpFetch::stopDriver() +{ + if (m_pHttpFetchDriver) + { + m_pHttpFetchDriver->stop(); + } +} diff --git a/src/util/httpfetch.h b/src/util/httpfetch.h index cbabdf6f1..a3b14ec04 100644 --- a/src/util/httpfetch.h +++ b/src/util/httpfetch.h @@ -18,11 +18,12 @@ #ifndef HTTPFETCH_H #define HTTPFETCH_H - - +#include "httpfetchdriver.h" +#include #include -class HttpFetch; +class GSockAddr; +using namespace LOG4CXX_NS; typedef int (*hf_callback)( void *, HttpFetch * ); @@ -45,7 +46,8 @@ class HttpFetch char * m_pRespContentType; int m_respBodyRead; int m_respHeaderBufLen; - char * m_pProxyServerAddr; + char * m_psProxyServerAddr; + GSockAddr * m_pProxyServerAddr; hf_callback m_callback; void * m_callbackArg; @@ -53,38 +55,61 @@ class HttpFetch char m_achHost[256]; char m_achResHeaderBuf[1024]; + HttpFetchDriver *m_pHttpFetchDriver; + int m_iTimeoutSec; + int m_iReqInited; + Logger * m_pLogger; + int m_iLoggerId; + int m_iEnableDebug; + int endReq( int res ); int getLine( char * &p, char * pEnd, char * &pLineBegin, char * &pLineEnd ); int allocateBuf( const char * pSaveFile ); int buildReq( const char * pMethod, const char * pURL, const char * pContentType = NULL ); - int startProcessReq( int nonblock, const char * pAddr ); + int startProcessReq( int nonblock, const GSockAddr & sockAddr); int sendReq(); int recvResp(); - + void startDriver(); + void stopDriver(); + int intiReq(const char * pURL, const char * pBody, int bodyLen, + const char * pSaveFile, const char * pContentType); + int getLoggerId() { return m_iLoggerId; } public: HttpFetch(); ~HttpFetch(); void setCallBack( hf_callback cb, void * pArg ) { m_callback = cb; m_callbackArg = pArg; } int getHttpFd() const { return m_fdHttp; } - int startReq( const char * pURL, int nonblock, const char * pBody = NULL, + + + int startReq( const char * pURL, int nonblock, int enableDriver = 1, const char * pBody = NULL, int bodyLen = 0, const char * pSaveFile = NULL, const char * pContentType = NULL, const char * addrServer = NULL ); + int startReq( const char * pURL, int nonblock, int enableDriver, const char * pBody, + int bodyLen, const char * pSaveFile, + const char * pContentType, const GSockAddr & sockAddr ); short getPollEvent() const; int processEvents( short revent ); int process(); int cancel(); - int getStatusCode() const { return m_statusCode; } + int getStatusCode() const { return m_statusCode; } const char * getRespContentType() const { return m_pRespContentType; } - VMemBuf * getResult() const { return m_pBuf; } + VMemBuf * getResult() const { return m_pBuf; } void releaseResult(); void reset(); void setProxyServerAddr( const char * pAddr ); const char * getProxyServerAddr() const - { return m_pProxyServerAddr; } - + { return m_psProxyServerAddr; } + + void closeConnection(); + void setTimeout(int timeoutSec) { m_iTimeoutSec = timeoutSec; } + int getTimeout() { return m_iTimeoutSec; } + void writeLog(const char *s) { m_pLogger->info( "HttpFetch[%d]: %s", getLoggerId(), s ); } + void enableDebug( int d ) { m_iEnableDebug = d; } + }; + #endif diff --git a/src/util/httpfetchdriver.cpp b/src/util/httpfetchdriver.cpp new file mode 100644 index 000000000..08940e391 --- /dev/null +++ b/src/util/httpfetchdriver.cpp @@ -0,0 +1,60 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#include "httpfetchdriver.h" +#include "httpfetch.h" +#include +#include + + +HttpFetchDriver::HttpFetchDriver(HttpFetch * pHttpFetch) +{ + m_pHttpFetch = pHttpFetch; + m_tmStart = time(NULL); +} + +int HttpFetchDriver::handleEvents(short int event) +{ + return m_pHttpFetch->processEvents( event ); +} + +void HttpFetchDriver::onTimer() +{ + if ( m_pHttpFetch->getTimeout() < 0 ) + return ; + + if ( time(NULL) - m_tmStart >= m_pHttpFetch->getTimeout() ) + { + m_pHttpFetch->setTimeout( -1 ); + m_pHttpFetch->closeConnection(); + } +} + +void HttpFetchDriver::start() +{ + setPollfd(); + Multiplexer *pMpl = HttpGlobals::getMultiplexer(); + if (pMpl) + pMpl->add( this, POLLIN|POLLOUT|POLLHUP|POLLERR ); +} + +void HttpFetchDriver::stop() +{ + Multiplexer *pMpl = HttpGlobals::getMultiplexer(); + if (pMpl) + pMpl->remove( this ); +} diff --git a/src/util/httpfetchdriver.h b/src/util/httpfetchdriver.h new file mode 100644 index 000000000..2e2156aca --- /dev/null +++ b/src/util/httpfetchdriver.h @@ -0,0 +1,43 @@ +/***************************************************************************** +* Open LiteSpeed is an open source HTTP server. * +* Copyright (C) 2013 LiteSpeed Technologies, Inc. * +* * +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 3 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see http://www.gnu.org/licenses/. * +*****************************************************************************/ +#ifndef HTTPFETCHDRIVER_H +#define HTTPFETCHDRIVER_H + +#include +#include + +class HttpFetch; + +class HttpFetchDriver : public EventReactor +{ + HttpFetch * m_pHttpFetch; + time_t m_tmStart; + +public: + virtual int handleEvents(short int event); + virtual void onTimer(); + + HttpFetchDriver(HttpFetch * pHttpFetch); + virtual ~HttpFetchDriver() { }; + HttpFetchDriver(const HttpFetchDriver& other) { }; + void start(); + void stop(); + +}; + +#endif // HTTPFETCHDRIVER_H diff --git a/src/util/logtracker.cpp b/src/util/logtracker.cpp index 1251d5f27..344264b71 100644 --- a/src/util/logtracker.cpp +++ b/src/util/logtracker.cpp @@ -19,9 +19,10 @@ #include LogTracker::LogTracker() : m_pLogger( NULL ) + , m_iLogIdBuilt( 0 ) { - m_logID.resizeBuf( MAX_LOGID_LEN + 1 ); - *( m_logID.buf() + MAX_LOGID_LEN ) = 0; + m_logId.resizeBuf( MAX_LOGID_LEN + 1 ); + *( m_logId.buf() + MAX_LOGID_LEN ) = 0; } LogTracker::~LogTracker() {} diff --git a/src/util/logtracker.h b/src/util/logtracker.h index abc7e9d57..7888f2d8c 100644 --- a/src/util/logtracker.h +++ b/src/util/logtracker.h @@ -25,21 +25,36 @@ #define MAX_LOGID_LEN 127 -class LogTracker : public LOG4CXX_NS::ILog +class LogTracker { - AutoStr2 m_logID; + AutoStr2 m_logId; LOG4CXX_NS::Logger* m_pLogger; + int m_iLogIdBuilt; + public: LogTracker(); ~LogTracker(); - AutoStr2& getIDBuf() { return m_logID; } - const char * getLogId() const { return m_logID.c_str(); } - const char * getLogId() { return m_logID.c_str(); } + AutoStr2& getIdBuf() { return m_logId; } + //const char * getLogId() const + //{ + //return m_logID.c_str(); } + const char * getLogId() + { + if ( m_iLogIdBuilt ) + return m_logId.c_str(); + m_iLogIdBuilt = 1; + return buildLogId(); + } LOG4CXX_NS::Logger* getLogger() const { return m_pLogger; } void setLogger( LOG4CXX_NS::Logger* pLogger) { m_pLogger = pLogger; } + + void setLogIdBuild( int n ) { m_iLogIdBuilt = n; } + int isLogIdBuilt() const { return m_iLogIdBuilt; } + virtual const char * buildLogId() = 0; + }; #endif diff --git a/src/util/loopbuf.cpp b/src/util/loopbuf.cpp index 1f38e4d81..e2ba22076 100644 --- a/src/util/loopbuf.cpp +++ b/src/util/loopbuf.cpp @@ -138,7 +138,7 @@ int LoopBuf::pop_front( int size ) errno = EINVAL; return -1; } - if (size ) + if ( size ) { int len = this->size() ; if ( size >= len ) @@ -148,7 +148,9 @@ int LoopBuf::pop_front( int size ) } else { - m_pHead = m_pBuf + ( m_pHead - m_pBuf + size ) % m_iCapacity ; + m_pHead += size; + if ( m_pHead >= m_pBufEnd ) + m_pHead -= m_iCapacity; } } return size; @@ -181,8 +183,13 @@ int LoopBuf::pop_back( int size ) void LoopBuf::used(int size) { - assert( size <= available() ); - m_pEnd = m_pBuf + ( m_pEnd - m_pBuf + size ) % m_iCapacity ; + register int avail = available(); + if ( size > avail ) + size = avail; + + m_pEnd += size; + if ( m_pEnd >= m_pBufEnd ) + m_pEnd -= m_iCapacity ; } int LoopBuf::contiguous() const @@ -194,7 +201,7 @@ int LoopBuf::contiguous() const } -void LoopBuf::iov_insert( IOVec &vect ) +void LoopBuf::iov_insert( IOVec &vect ) const { int size = this->size(); if ( size > 0 ) @@ -212,7 +219,7 @@ void LoopBuf::iov_insert( IOVec &vect ) } } -void LoopBuf::iov_append( IOVec &vect ) +void LoopBuf::iov_append( IOVec &vect ) const { int size = this->size(); if ( size > 0 ) @@ -255,3 +262,16 @@ int LoopBuf::guarantee(int size) return 0; return reserve(size + this->size() + 1); } + +void LoopBuf::update( int offset, const char * pBuf, int size ) +{ + char * p = getPointer( offset ); + const char * pEnd = pBuf + size; + while( pBuf < pEnd ) + { + *p++ = *pBuf++; + if ( p == m_pBufEnd ) + p = m_pBuf; + } +} + diff --git a/src/util/loopbuf.h b/src/util/loopbuf.h index f1c09ea53..4be435a96 100644 --- a/src/util/loopbuf.h +++ b/src/util/loopbuf.h @@ -43,28 +43,33 @@ class LoopBuf explicit LoopBuf(int size = LOOPBUFUNIT); ~LoopBuf(); int available() const - { return ( m_pHead > m_pEnd ) ? m_pHead - m_pEnd - 1 - : m_pHead + m_iCapacity - m_pEnd - 1; + { + register int ret = m_pHead - m_pEnd - 1; + if ( ret >= 0 ) + return ret; + return ret + m_iCapacity; } + // return the size of free memory block, could be smaller than available() + // as it will start use the free space at the beginning once + // reach the end. int contiguous() const; + // return the size of memory block, could be smaller than size() + // as it will start use the free space at the beginning once + // reach the end. int blockSize() const { return ( m_pHead > m_pEnd ) ? m_pBufEnd - m_pHead : m_pEnd - m_pHead; } - char * begin() { return m_pHead; } - char * end() { return m_pEnd; } + char * begin() const { return m_pHead; } + char * end() const { return m_pEnd; } - const char * begin() const { return m_pHead; } - const char * end() const { return m_pEnd; } char * getPointer(int size) const { return m_pBuf + ( m_pHead - m_pBuf + size ) % m_iCapacity ; } - char * getPointer(int size) - { return m_pBuf + ( m_pHead - m_pBuf + size ) % m_iCapacity ; } int getOffset( const char * p ) const { @@ -79,15 +84,26 @@ class LoopBuf int capacity() const { return m_iCapacity; } int size() const - { return ( m_pEnd - m_pHead + m_iCapacity ) % m_iCapacity ;} - + { + register int ret = m_pEnd - m_pHead; + if ( ret >= 0 ) + return ret; + return ret + m_iCapacity; + } + int reserve( int size ) { return allocate(size) ; } int append( const char * pBuf, int size ); - - int append( const char * pBuf ) - { return append( pBuf, strlen( pBuf ) ); } + + // NOTICE: no boundary check for maximum performance, should make sure + // buffer has available space before calling this function. + void append( char ch ) + { + *m_pEnd++ = ch; + if ( m_pEnd == m_pBufEnd ) + m_pEnd = m_pBuf; + } int guarantee(int size); @@ -98,27 +114,24 @@ class LoopBuf return pPos ; } - const char* inc(const char * &pPos) const - { - if ( ++pPos == m_pBufEnd ) - pPos = m_pBuf ; - return pPos ; - } bool empty() const { return ( m_pHead == m_pEnd ); } bool full() const - { return (m_pEnd - m_pHead + 1) % m_iCapacity == 0 ; } + { return size() == m_iCapacity - 1; } int moveTo( char * pBuf, int size ); int pop_front( int size ); int pop_back( int size ); - void getIOvec( IOVec &vect ) { iov_append( vect ); } + void getIOvec( IOVec &vect ) const { iov_append( vect ); } - void iov_insert( IOVec &vect ); - void iov_append( IOVec &vect ); + void iov_insert( IOVec &vect ) const; + void iov_append( IOVec &vect ) const; void swap( LoopBuf& rhs ); + + void update( int offset, const char * pBuf, int size ); + }; #endif diff --git a/src/util/pcregex.cpp b/src/util/pcregex.cpp index 92d3b39be..ced9e6e21 100644 --- a/src/util/pcregex.cpp +++ b/src/util/pcregex.cpp @@ -98,7 +98,13 @@ int Pcregex::compile(const char * regex, int options, int matchLimit, int recurs m_regex = pcre_compile(regex, options, &error, &erroffset, NULL); if (m_regex == NULL) return -1; - m_extra = pcre_study(m_regex, PCRE_STUDY_JIT_COMPILE, &error); + m_extra = pcre_study(m_regex, +#if defined( _USE_PCRE_JIT_)&&!defined(__sparc__) && !defined(__sparc64__) && defined( PCRE_CONFIG_JIT ) + PCRE_STUDY_JIT_COMPILE, +#else + 0, +#endif + &error); if ( matchLimit > 0 ) { m_extra->match_limit = matchLimit; diff --git a/src/util/pool.cpp b/src/util/pool.cpp index 8718451b7..0d662cbc6 100644 --- a/src/util/pool.cpp +++ b/src/util/pool.cpp @@ -135,8 +135,6 @@ Pool::reallocate(void* p, size_t old_sz, size_t new_sz) { - void* result; - size_t copy_sz; old_sz = roundUp(old_sz); new_sz = roundUp(new_sz); if (old_sz == new_sz) return(p); diff --git a/src/util/ssnprintf.h b/src/util/ssnprintf.h index b40731d88..7b016fcc5 100644 --- a/src/util/ssnprintf.h +++ b/src/util/ssnprintf.h @@ -28,7 +28,7 @@ inline int safe_snprintf(char *str, size_t size, const char *format, ...) int ret = vsnprintf(str, size, format, ap); va_end( ap ); - if (ret > size) + if ( ( unsigned int )ret > size) ret = size; return ret; diff --git a/src/util/stringtool.cpp b/src/util/stringtool.cpp index 0d18d1734..a47c03a24 100644 --- a/src/util/stringtool.cpp +++ b/src/util/stringtool.cpp @@ -20,6 +20,7 @@ #include #include #include +#include StringTool::StringTool(){ } @@ -556,5 +557,11 @@ int StringTool::unescapeQuote( char * pBegin, char * pEnd, int ch ) return n; } - +void StringTool::getMd5(const char *src, int len, unsigned char * dstBin) +{ + MD5_CTX ctx; + MD5_Init( &ctx ); + MD5_Update( &ctx, src, len); + MD5_Final( dstBin, &ctx ); +} diff --git a/src/util/stringtool.h b/src/util/stringtool.h index 4a2b8dc5f..4516c12d0 100644 --- a/src/util/stringtool.h +++ b/src/util/stringtool.h @@ -108,6 +108,8 @@ class StringTool const char * pEnd, char searched ); static int str_off_t( char * pBuf, int len, off_t val ); static int unescapeQuote( char * pBegin, char * pEnd, int ch ); + + static void getMd5(const char *src, int len, unsigned char * dstBin); }; #endif diff --git a/src/util/sysinfo/linux_nicdetect.cpp b/src/util/sysinfo/linux_nicdetect.cpp index 705e6a8af..09980d9f8 100644 --- a/src/util/sysinfo/linux_nicdetect.cpp +++ b/src/util/sysinfo/linux_nicdetect.cpp @@ -93,11 +93,10 @@ NICDetect::get_ifi_info(int family, int doaliases) { struct ifi_info *ifi, *ifihead, **ifipnext; int sockfd, len, flags, myflags; - char *ptr, *buf, lastname[IFNAMSIZ], *cptr; + char *buf, lastname[IFNAMSIZ], *cptr; struct ifconf ifc; struct ifreq *ifr, ifrcopy; struct sockaddr_in *sinptr; - struct sockaddr_in6 *sinptr6; if ( family == AF_INET6 ) return parse_proc_net(); sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); @@ -203,7 +202,6 @@ NICDetect::get_ifi_info(int family, int doaliases) } break; case AF_INET6: - sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; if (ifi->ifi_addr == NULL) { ifi->ifi_addr = (sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); diff --git a/src/util/vmembuf.cpp b/src/util/vmembuf.cpp index 4bab70d62..36c5cef35 100644 --- a/src/util/vmembuf.cpp +++ b/src/util/vmembuf.cpp @@ -98,7 +98,7 @@ void VMemBuf::deallocate() { if ( m_fd != -1) { - int ret = ::close( m_fd ); + ::close( m_fd ); m_fd = -1; } unlink( m_sFileName.c_str() ); @@ -144,7 +144,7 @@ int VMemBuf::shrinkBuf( long size ) size = 0; if (( m_type == VMBUF_FILE_MAP )&&( m_fd != -1 )) { - if ( m_curTotalSize > size ) + if ( m_curTotalSize > (unsigned long) size ) ftruncate( m_fd, size ); } BlockBuf * pBuf; @@ -202,7 +202,7 @@ int VMemBuf::reinit(int TargetSize) { if (( TargetSize < 1024 * 1024 )&& ( s_iMaxAnonMapBlocks - s_iCurAnonMapBlocks > s_iMaxAnonMapBlocks / 5 )&& - ( TargetSize < (s_iMaxAnonMapBlocks - s_iCurAnonMapBlocks) * s_iBlockSize )) + ( (unsigned int) TargetSize < (s_iMaxAnonMapBlocks - s_iCurAnonMapBlocks) * s_iBlockSize )) { deallocate(); if ( set( VMBUF_ANON_MAP , getBlockSize() ) == -1 ) @@ -264,7 +264,7 @@ void VMemBuf::reset() BlockBuf * VMemBuf::getAnonMapBlock(int size) { BlockBuf *pBlock; - if ( size == s_iBlockSize ) + if ( ( unsigned int )size == s_iBlockSize ) { if ( !s_pAnonPool->empty() ) { @@ -443,6 +443,7 @@ int VMemBuf::set(const char * pFileName, int size) perror( "Failed to open temp file for swapping" ); return -1; } + fcntl( m_fd, F_SETFD, FD_CLOEXEC ); } @@ -817,7 +818,6 @@ int VMemBuf::copyToFile( size_t startOff, size_t len, if ( ftruncate( fd, destSize ) == -1 ) return -1; } - off_t curSize = st.st_size; BlockBuf destBlock; char * pPos = mapTmpBlock( fd, destBlock, destStartOff, PROT_WRITE ); int ret = 0;