Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Fix [Bug 2891171]: URL checking too strict when using multiple question marks |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
81e45883f4b4d986f69a9d5eff4b82ba |
| User & Date: | nijtmans 2009-11-11 06:49:04.000 |
Context
|
2009-11-12
| ||
| 16:31 | * generic/tclClock.c (TclClockInit): Do not create [clock] support commands in sa... check-in: b33ef2e156 user: dgp tags: trunk | |
|
2009-11-11
| ||
| 06:49 | Fix [Bug 2891171]: URL checking too strict when using multiple question marks check-in: 81e45883f4 user: nijtmans tags: trunk | |
|
2009-11-10
| ||
| 23:50 | Fix [Bug 2888099] (close discards ENOSPC error) by saving the errno from the first of two FlushChann... check-in: c4da5b0446 user: ferrieux tags: trunk | |
Changes
Changes to ChangeLog.
1 2 3 4 5 6 7 | 2009-11-11 Alexandre Ferrieux <ferrieux@users.sourceforge.net> * generic/tclIO.c: Fix [Bug 2888099] (close discards ENOSPC error) by saving the errno from the first of two FlushChannel()s. Uneasy to test; might need specific channel drivers. Four-hands with aku. | > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 2009-11-11 Jan Nijtmans <nijtmans@users.sf.net> * library/http/http.tcl (http::geturl): [Bug 2891171]: URl checking too strict when using multiple question marks * tests/http.test * library/http/pkgIndex.tcl: Bump to http 2.8.2 * unix/Makefile.in: * win/Makefile.in: 2009-11-11 Alexandre Ferrieux <ferrieux@users.sourceforge.net> * generic/tclIO.c: Fix [Bug 2888099] (close discards ENOSPC error) by saving the errno from the first of two FlushChannel()s. Uneasy to test; might need specific channel drivers. Four-hands with aku. |
| ︙ | ︙ |
Changes to library/http/http.tcl.
1 2 3 4 5 6 7 8 9 10 | # http.tcl -- # # Client-side HTTP for GET, POST, and HEAD commands. These routines can # be used in untrusted code that uses the Safesock security policy. # These procedures use a callback interface to avoid using vwait, which # is not defined in the safe base. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# http.tcl --
#
# Client-side HTTP for GET, POST, and HEAD commands. These routines can
# be used in untrusted code that uses the Safesock security policy.
# These procedures use a callback interface to avoid using vwait, which
# is not defined in the safe base.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: http.tcl,v 1.78 2009/11/11 06:49:05 nijtmans Exp $
package require Tcl 8.6
# Keep this in sync with pkgIndex.tcl and with the install directories in
# Makefiles
package provide http 2.8.2
namespace eval http {
# Allow resourcing to not clobber existing data
variable http
if {![info exists http]} {
array set http {
|
| ︙ | ︙ | |||
96 97 98 99 100 101 102 | # # Debugging output -- define this to observe HTTP/1.1 socket usage. # Should echo any args received. # # Arguments: # msg Message to output # | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#
# Debugging output -- define this to observe HTTP/1.1 socket usage.
# Should echo any args received.
#
# Arguments:
# msg Message to output
#
if {[info command http::Log] eq {}} {proc http::Log {args} {}}
# http::register --
#
# See documentation for details.
#
# Arguments:
# proto URL protocol prefix, e.g. https
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
if {$errormsg ne ""} {
set state(error) [list $errormsg $errorInfo $errorCode]
set state(status) "error"
}
if {
($state(status) eq "timeout") || ($state(status) eq "error") ||
([info exists state(connection)] && ($state(connection) eq "close"))
| | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
if {$errormsg ne ""} {
set state(error) [list $errormsg $errorInfo $errorCode]
set state(status) "error"
}
if {
($state(status) eq "timeout") || ($state(status) eq "error") ||
([info exists state(connection)] && ($state(connection) eq "close"))
} {
CloseSocket $state(sock) $token
}
if {[info exists state(after)]} {
after cancel $state(after)
}
if {[info exists state(-command)] && !$skipCB} {
if {[catch {eval $state(-command) {$token}} err]} {
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 |
set pat ^-(?:[join $options |])$
foreach {flag value} $args {
if {[regexp -- $pat $flag]} {
# Validate numbers
if {
[info exists type($flag)] &&
![string is $type($flag) -strict $value]
| | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
set pat ^-(?:[join $options |])$
foreach {flag value} $args {
if {[regexp -- $pat $flag]} {
# Validate numbers
if {
[info exists type($flag)] &&
![string is $type($flag) -strict $value]
} {
unset $token
return -code error \
"Bad value for $flag ($value), must be $type($flag)"
}
set state($flag) $value
} else {
unset $token
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 | ( [^@/\#?]+ # <userinfo part of authority> ) @ )? ( [^/:\#?]+ ) # <host part of authority> (?: : (\d+) )? # <port part of authority> )? | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
(
[^@/\#?]+ # <userinfo part of authority>
) @
)?
( [^/:\#?]+ ) # <host part of authority>
(?: : (\d+) )? # <port part of authority>
)?
( / [^\#]*)? # <path> (including query)
(?: \# (.*) )? # <fragment>
$
}
# Phase one: parse
if {![regexp -- $URLmatcher $url -> proto user host port srvurl]} {
unset $token
|
| ︙ | ︙ | |||
724 725 726 727 728 729 730 | # # It is possible to have both the read and write fileevents active at # this point. The only scenario it seems to affect is a server that # closes the connection without reading the POST data. (e.g., early # versions TclHttpd in various error cases). Depending on the # platform, the client may or may not be able to get the response from # the server because of the error it will get trying to write the post | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
#
# It is possible to have both the read and write fileevents active at
# this point. The only scenario it seems to affect is a server that
# closes the connection without reading the POST data. (e.g., early
# versions TclHttpd in various error cases). Depending on the
# platform, the client may or may not be able to get the response from
# the server because of the error it will get trying to write the post
# data. Having both fileevents active changes the timing and the
# behavior, but no two platforms (among Solaris, Linux, and NT) behave
# the same, and none behave all that well in any case. Servers should
# always read their POST data if they expect the client to read their
# response.
if {$isQuery || $isQueryChannel} {
puts $sock "Content-Type: $state(-type)"
|
| ︙ | ︙ | |||
755 756 757 758 759 760 761 |
wait $token
if {$state(status) eq "error"} {
# Something went wrong, so throw the exception, and the
# enclosing catch will do cleanup.
return -code error [lindex $state(error) 0]
}
}
| | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
wait $token
if {$state(status) eq "error"} {
# Something went wrong, so throw the exception, and the
# enclosing catch will do cleanup.
return -code error [lindex $state(error) 0]
}
}
} err]} {
# The socket probably was never connected, or the connection dropped
# later.
# Clean up after events and such, but DON'T call the command callback
# (if available) because we're going to throw an exception from here
# instead.
|
| ︙ | ︙ | |||
863 864 865 866 867 868 869 |
proc http::Connect {token} {
variable $token
upvar 0 $token state
global errorInfo errorCode
if {
[eof $state(sock)] ||
[string length [fconfigure $state(sock) -error]]
| | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 |
proc http::Connect {token} {
variable $token
upvar 0 $token state
global errorInfo errorCode
if {
[eof $state(sock)] ||
[string length [fconfigure $state(sock) -error]]
} {
Finish $token "connect failed [fconfigure $state(sock) -error]" 1
} else {
set state(status) connect
fileevent $state(sock) writable {}
}
return
}
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 |
set outStr [read $state(-querychannel) $state(-queryblocksize)]
puts -nonewline $sock $outStr
incr state(queryoffset) [string length $outStr]
if {[eof $state(-querychannel)]} {
set done 1
}
}
| | | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 |
set outStr [read $state(-querychannel) $state(-queryblocksize)]
puts -nonewline $sock $outStr
incr state(queryoffset) [string length $outStr]
if {[eof $state(-querychannel)]} {
set done 1
}
}
} err]} {
# Do not call Finish here, but instead let the read half of the socket
# process whatever server reply there is to get.
set state(posterror) $err
set done 1
}
if {$done} {
|
| ︙ | ︙ | |||
993 994 995 996 997 998 999 |
# and no more data is sent. We can tell and must finish up now -
# not later.
if {
!(([info exists state(connection)]
&& ($state(connection) eq "close"))
|| [info exists state(transfer)])
&& ($state(totalsize) == 0)
| | | | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
# and no more data is sent. We can tell and must finish up now -
# not later.
if {
!(([info exists state(connection)]
&& ($state(connection) eq "close"))
|| [info exists state(transfer)])
&& ($state(totalsize) == 0)
} {
Log "body size is 0 and no events likely - complete."
Eof $token
return
}
# We have to use binary translation to count bytes properly.
fconfigure $sock -translation binary
if {
$state(-binary) || ![string match -nocase text* $state(type)]
} {
# Turn off conversions for non-text data
set state(binary) 1
}
if {[info exists state(-channel)]} {
if {$state(binary) || [llength [ContentEncoding $token]]} {
fconfigure $state(-channel) -translation binary
}
|
| ︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 |
} else {
Log "final chunk part"
Eof $token
}
} elseif {
[info exists state(transfer)]
&& $state(transfer) eq "chunked"
| | | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
} else {
Log "final chunk part"
Eof $token
}
} elseif {
[info exists state(transfer)]
&& $state(transfer) eq "chunked"
} {
set size 0
set chunk [getTextLine $sock]
set n [string length $chunk]
if {[string trim $chunk] ne ""} {
scan $chunk %x size
if {$size != 0} {
set bl [fconfigure $sock -blocking]
|
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 |
if {$n >= 0} {
incr state(currentsize) $n
}
# If Content-Length - check for end of data.
if {
($state(totalsize) > 0)
&& ($state(currentsize) >= $state(totalsize))
| | | | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 |
if {$n >= 0} {
incr state(currentsize) $n
}
# If Content-Length - check for end of data.
if {
($state(totalsize) > 0)
&& ($state(currentsize) >= $state(totalsize))
} {
Eof $token
}
}
} err]} {
return [Finish $token $err]
} else {
if {[info exists state(-progress)]} {
eval $state(-progress) \
[list $token $state(totalsize) $state(currentsize)]
}
}
|
| ︙ | ︙ | |||
1393 1394 1395 1396 1397 1398 1399 |
proc http::ProxyRequired {host} {
variable http
if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} {
if {
![info exists http(-proxyport)] ||
![string length $http(-proxyport)]
| | | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
proc http::ProxyRequired {host} {
variable http
if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} {
if {
![info exists http(-proxyport)] ||
![string length $http(-proxyport)]
} {
set http(-proxyport) 8080
}
return [list $http(-proxyhost) $http(-proxyport)]
}
}
# http::CharsetToEncoding --
|
| ︙ | ︙ | |||
1477 1478 1479 1480 1481 1482 1483 |
while {$size && ![chan eof $chan]} {
set part [chan read $chan $size]
incr size -[string length $part]
append chunk $part
}
if {[catch {
uplevel #0 [linsert $command end $chunk]
| | | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 |
while {$size && ![chan eof $chan]} {
set part [chan read $chan $size]
incr size -[string length $part]
append chunk $part
}
if {[catch {
uplevel #0 [linsert $command end $chunk]
}]} {
http::Log "Error in callback: $::errorInfo"
}
if {[string length $chunk] == 0} {
# channel might have been closed in the callback
catch {chan event $chan readable {}}
return
}
|
| ︙ | ︙ |
Changes to library/http/pkgIndex.tcl.
1 |
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
| | | 1 2 |
if {![package vsatisfies [package provide Tcl] 8.6]} {return}
package ifneeded http 2.8.2 [list tclPkgSetup $dir http 2.8.2 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}]
|
Changes to unix/Makefile.in.
1 2 3 4 5 6 | # # This file is a Makefile for Tcl. If it has the name "Makefile.in" then it is # a template for a Makefile; to generate the actual Makefile, run # "./configure", which is a configuration script generated by the "autoconf" # program (constructs like "@foo@" will get replaced in the actual Makefile. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # # This file is a Makefile for Tcl. If it has the name "Makefile.in" then it is # a template for a Makefile; to generate the actual Makefile, run # "./configure", which is a configuration script generated by the "autoconf" # program (constructs like "@foo@" will get replaced in the actual Makefile. # # RCS: @(#) $Id: Makefile.in,v 1.280 2009/11/11 06:49:05 nijtmans Exp $ VERSION = @TCL_VERSION@ MAJOR_VERSION = @TCL_MAJOR_VERSION@ MINOR_VERSION = @TCL_MINOR_VERSION@ PATCH_LEVEL = @TCL_PATCH_LEVEL@ #-------------------------------------------------------------------------- |
| ︙ | ︙ | |||
819 820 821 822 823 824 825 | $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing library http1.0 directory"; @for i in $(TOP_DIR)/library/http1.0/*.tcl ; \ do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/http1.0; \ done; | | | | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing library http1.0 directory"; @for i in $(TOP_DIR)/library/http1.0/*.tcl ; \ do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/http1.0; \ done; @echo "Installing package http 2.8.2 as a Tcl Module"; @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.2.tm; @echo "Installing library opt0.4 directory"; @for i in $(TOP_DIR)/library/opt/*.tcl ; \ do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/opt0.4; \ done; @echo "Installing package msgcat 1.4.2 as a Tcl Module"; @$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.4.2.tm; |
| ︙ | ︙ |
Changes to win/Makefile.in.
1 2 3 4 5 6 | # # This file is a Makefile for Tcl. If it has the name "Makefile.in" then it # is a template for a Makefile; to generate the actual Makefile, run # "./configure", which is a configuration script generated by the "autoconf" # program (constructs like "@foo@" will get replaced in the actual Makefile. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # # This file is a Makefile for Tcl. If it has the name "Makefile.in" then it # is a template for a Makefile; to generate the actual Makefile, run # "./configure", which is a configuration script generated by the "autoconf" # program (constructs like "@foo@" will get replaced in the actual Makefile. # # RCS: @(#) $Id: Makefile.in,v 1.162 2009/11/11 06:49:05 nijtmans Exp $ VERSION = @TCL_VERSION@ #-------------------------------------------------------------------------- # Things you can change to personalize the Makefile for your own site (you can # make these changes in either Makefile.in or Makefile, but changes to # Makefile will get lost if you re-run the configuration script). |
| ︙ | ︙ | |||
697 698 699 700 701 702 703 | $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing library http1.0 directory"; @for j in $(ROOT_DIR)/library/http1.0/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; | | | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing library http1.0 directory"; @for j in $(ROOT_DIR)/library/http1.0/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; @echo "Installing package http 2.8.2 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.2.tm; @echo "Installing library opt0.4 directory"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done; @echo "Installing package msgcat 1.4.2 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.4.2.tm; |
| ︙ | ︙ |