From baf9ec7e2de72db256e852153bb4213dea2b3485 Mon Sep 17 00:00:00 2001 From: kjnash Date: Fri, 24 Jul 2020 18:43:28 +0000 Subject: Fix for bug cb0373bb33. In HTTP/1.1 the response header "Connection", if absent, must default to "keep-alive". Add test http11-1.13 and bump http version to 2.9.3. --- library/http/http.tcl | 33 ++++++++++++++++++++++++++++----- library/http/pkgIndex.tcl | 2 +- library/manifest.txt | 2 +- tests/http11.test | 37 +++++++++++++++++++++++++++++++++++++ tests/httpPipeline.test | 2 +- unix/Makefile.in | 4 ++-- win/Makefile.in | 4 ++-- 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/library/http/http.tcl b/library/http/http.tcl index a7ed771..ccec40d 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -11,7 +11,7 @@ package require Tcl 8.6- # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles -package provide http 2.9.2 +package provide http 2.9.3 namespace eval http { # Allow resourcing to not clobber existing data @@ -734,7 +734,7 @@ proc http::geturl {url args} { body {} status "" http "" - connection close + connection keep-alive } set state(-keepalive) $defaultKeepalive set state(-strict) $strict @@ -1054,7 +1054,7 @@ proc http::geturl {url args} { } # Do not automatically close the connection socket. - set state(connection) {} + set state(connection) keep-alive } } @@ -2725,8 +2725,31 @@ proc http::Event {sock token} { } proxy-connection - connection { - set state(connection) \ - [string trim [string tolower $value]] + set tmpHeader [string trim [string tolower $value]] + # RFC 7230 Section 6.1 states that a comma-separated + # list is an acceptable value. According to + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection + # any comma-separated list implies keep-alive, but I + # don't see this in the RFC so we'll play safe and + # scan any list for "close". + if {$tmpHeader in {close keep-alive}} { + # The common cases, continue. + } elseif {[string first , $tmpHeader] == -1} { + # Not a comma-separated list, not "close", + # therefore "keep-alive". + set tmpHeader keep-alive + } else { + set tmpHeader keep-alive + set tmpCsl [split $tmpHeader ,] + # Optional whitespace either side of separator. + foreach el $tmpCsl { + if {[string trim $el] eq {close}} { + set tmpHeader close + break + } + } + } + set state(connection) $tmpHeader } set-cookie { if {$http(-cookiejar) ne ""} { diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index 4f5eafb..43cd86b 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.6-]} {return} -package ifneeded http 2.9.2 [list tclPkgSetup $dir http 2.9.2 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] +package ifneeded http 2.9.3 [list tclPkgSetup $dir http 2.9.3 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/library/manifest.txt b/library/manifest.txt index 5ae0eb7..3a7ba54 100644 --- a/library/manifest.txt +++ b/library/manifest.txt @@ -5,7 +5,7 @@ apply {{dir} { set ::test [info script] set isafe [interp issafe] foreach {safe package version file} { - 0 http 2.9.2 {http http.tcl} + 0 http 2.9.3 {http http.tcl} 1 msgcat 1.7.1 {msgcat msgcat.tcl} 1 opt 0.4.7 {opt optparse.tcl} 0 cookiejar 0.2.0 {cookiejar cookiejar.tcl} diff --git a/tests/http11.test b/tests/http11.test index 1e30802..6d93d36 100644 --- a/tests/http11.test +++ b/tests/http11.test @@ -60,6 +60,20 @@ proc meta {tok {key ""}} { return $meta } +proc state {tok {key ""}} { + upvar 1 $tok state + if {$key ne ""} { + if {[array names state -exact $key] ne {}} { + return $state($key) + } else { + return "" + } + } + set res [array get state] + dict set res body + return $res +} + proc check_crc {tok args} { set crc [meta $tok x-crc32] set data [expr {[llength $args] ? [lindex $args 0] : [http::data $tok]}] @@ -241,6 +255,29 @@ test http11-1.12 "normal,identity,chunked" -setup { halt_httpd } -result {ok {HTTP/1.1 200 OK} ok {} chunked} +test http11-1.13 "normal, 1.1 and keepalive as server default, no zip" -setup { + variable httpd [create_httpd] + set zipTmp [http::config -zip] + http::config -zip 0 +} -body { + set tok [http::geturl http://localhost:$httpd_port/testdoc.html?transfer= \ + -protocol 1.1 -keepalive 1 -timeout 10000] + http::wait $tok + set res1 [list [http::status $tok] [http::code $tok] [check_crc $tok] \ + [meta $tok connection] [meta $tok transfer-encoding] [state $tok reusing] [state $tok connection]] + set toj [http::geturl http://localhost:$httpd_port/testdoc.html?transfer= \ + -protocol 1.1 -keepalive 1 -timeout 10000] + http::wait $toj + set res2 [list [http::status $toj] [http::code $toj] [check_crc $toj] \ + [meta $toj connection] [meta $toj transfer-encoding] [state $toj reusing] [state $toj connection]] + concat $res1 -- $res2 +} -cleanup { + http::cleanup $tok + http::cleanup $toj + halt_httpd + http::config -zip $zipTmp +} -result {ok {HTTP/1.1 200 OK} ok {} {} 0 keep-alive -- ok {HTTP/1.1 200 OK} ok {} {} 1 keep-alive} + # ------------------------------------------------------------------------- test http11-2.0 "-channel" -setup { diff --git a/tests/httpPipeline.test b/tests/httpPipeline.test index 8de79b9..de1a7d8 100644 --- a/tests/httpPipeline.test +++ b/tests/httpPipeline.test @@ -11,7 +11,7 @@ package require tcltest 2 namespace import -force ::tcltest::* -package require http 2.8 +package require http 2.9 set sourcedir [file normalize [file dirname [info script]]] source [file join $sourcedir httpTest.tcl] diff --git a/unix/Makefile.in b/unix/Makefile.in index 21967bd..b7a4d03 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -1039,9 +1039,9 @@ install-libraries: libraries @for i in $(TOP_DIR)/library/cookiejar/*.gz; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/cookiejar0.2"; \ done - @echo "Installing package http 2.9.2 as a Tcl Module" + @echo "Installing package http 2.9.3 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl \ - "$(MODULE_INSTALL_DIR)/8.6/http-2.9.2.tm" + "$(MODULE_INSTALL_DIR)/8.6/http-2.9.3.tm" @echo "Installing package opt 0.4.7" @for i in $(TOP_DIR)/library/opt/*.tcl; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ diff --git a/win/Makefile.in b/win/Makefile.in index 89f01e4..7c5c1bc 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -875,8 +875,8 @@ install-libraries: libraries install-tzdata install-msgs do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/cookiejar0.2"; \ done; - @echo "Installing package http 2.9.2 as a Tcl Module"; - @$(COPY) $(ROOT_DIR)/library/http/http.tcl "$(MODULE_INSTALL_DIR)/8.6/http-2.9.2.tm"; + @echo "Installing package http 2.9.3 as a Tcl Module"; + @$(COPY) $(ROOT_DIR)/library/http/http.tcl "$(MODULE_INSTALL_DIR)/8.6/http-2.9.3.tm"; @echo "Installing package opt 0.4.7"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ -- cgit v0.12