summaryrefslogtreecommitdiffstats
path: root/rubbos/app/httpd-2.0.64/modules/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/proxy')
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/.deps0
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/.indent.pro58
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/CHANGES223
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/Makefile8
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/Makefile.in3
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/NWGNUmakefile247
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxy261
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxycon254
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyftp260
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyhtp263
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/config.m434
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/libproxy.exp1
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.c1181
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.dsp140
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.h255
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_connect.dsp136
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_ftp.dsp136
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_http.dsp136
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/modules.mk3
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/proxy_connect.c377
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/proxy_ftp.c1936
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/proxy_http.c1824
-rw-r--r--rubbos/app/httpd-2.0.64/modules/proxy/proxy_util.c1120
23 files changed, 8856 insertions, 0 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/.deps b/rubbos/app/httpd-2.0.64/modules/proxy/.deps
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/.deps
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/.indent.pro b/rubbos/app/httpd-2.0.64/modules/proxy/.indent.pro
new file mode 100644
index 00000000..e2cd357a
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/.indent.pro
@@ -0,0 +1,58 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tapr_bucket_brigade
+-Tapr_pool_t
+-Tap_filter_t
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
+-Tproxy_server_conf
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/CHANGES b/rubbos/app/httpd-2.0.64/modules/proxy/CHANGES
new file mode 100644
index 00000000..73a9228d
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/CHANGES
@@ -0,0 +1,223 @@
+******************************************
+* PLEASE NOTE: Now that development for *
+* mod_proxy has been folded back into *
+* the httpd-2.0 tree, this file has *
+* been depreciated. Proxy changes should *
+* be noted in httpd-2.0's CHANGES file. *
+* This file exists for historical *
+* purposes. *
+******************************************
+
+mod_proxy changes for httpd 2.0.29-dev
+ *) don't do keepalives for sub-requests. [Ian Holsman]
+
+ *) fix up proxypass handling [Ian Holsman]
+
+ *) don't send If-Modified-Since, Cache-Control, or If-None-Match on
+ a subrequest [Ian Holsman]
+
+mod_proxy changes for httpd 2.0.26-dev
+ *) Add New option 'HTTPProxyOverrideReturnedErrors'. By Turning the
+ Flag on, you will mask the error pages returned by the proxied
+ server, and will it will be handled as if your server generated
+ the error. This change was put in so that a 404 on a included
+ r-proxied component will act in the same manner as a 404 on a
+ included file. [Ian Holsman <ianh@cnet.com>]
+
+mod_proxy changes for httpd 2.0.25-dev
+
+ *) Split proxy: space using <Proxy[Match] > directive blocks from
+ the <Directory[Match] > and <Files[Match] > blocks. Mod_proxy
+ now bypasses the directory and files testing phase (and skips
+ the http TRACE default handler on it's own, as well). Note that
+ <Location > blocks continue to be processed for proxy: requests.
+ [William Rowe <wrowe@covalent.net>]
+
+ *) apr_uri type/function namespace changes in apr_uri functions
+ [Doug MacEachern <dougm@covalent.net>]
+
+mod_proxy changes for httpd 2.0.23-dev
+
+ *) break the proxy_http_handler into multiple smaller functions.
+ [John Barbee <barbee@veribox.net>]
+
+ *) Fix the proxy when the origin server sends back a 100
+ Continue response. [John Barbee <barbee@veribox.net>]
+
+ *) Change 'readbytes' from apr_size_t to apr_off_t due to change
+ in ap_get_brigade's parameters [John Barbee <barbee@veribox.net>]
+
+mod_proxy changes for httpd 2.0.20-dev
+ *) Timeout added for backend connections.
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+ *) Fix abort code path in proxy_http.c, similar to FTP fix.
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) Fix FTP ABOR command execution path.
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+ *) FTP return code variable cleanup; fixed problem in login
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) Get PORT working again in the ftp proxy.
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+ *) Return result code check for FTP QUIT, after fixing
+ problems with passive connection handling.
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+ *) Reorganize ap_proxy_string_read() internally to not process eos
+ buckets.
+ [Chuck Murcko <chuck@topsail.org>]
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+ *) Remove result code check for FTP QUIT command. Some servers send
+ nothing at all back in response to QUIT.
+ [Chuck Murcko <chuck@topsail.org>]
+ [Victor Orlikowski <v.j.orlikowski@gte.net>]
+
+mod_proxy changes for httpd 2.0.19
+
+ *) Reverse previous patch since the core reverted.
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) Remove indirection on number of bytes to read for input filters.
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) Fixed a problem with directory listing corruption in the
+ PROXY_DIR filter.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) mod_proxy and the proxy submodules now build properly as DSOs.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Stopped the HTTP proxy from trying to read entity bodies when there
+ wasn't one (response was 1xx, 204, 205 or 304).
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Made sure dates were canonicalised correctly when passed to the client
+ browser through the HTTP proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Split each individual proxy protocol into separate modules.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Added Max-Forwards support for all request types so as to prevent
+ loops.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fix warnings about byte count type on Darwin (connect handler).
+ [Chuck Murcko <chuck@topsail.org>]
+
+mod_proxy changes for httpd 2.0.18
+
+ *) IPV6 EPSV support for IPV6 in FTP proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) FTP directory filter works now.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fixed some thread-safety issues with the HTTP proxy in mod_proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) PASV FTP works now.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Reworked the line-at-a-time read from the control connection to
+ workaround a stray empty bucket returned by the HTTP_IN filter.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Stopped the CORE filter from sending off an HTTP response when a
+ CONNECT tunnel was closed.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fixed the poll() loop in proxy_connect.c -> it works now!!!
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Converted send_dir() to ap_proxy_send_dir_filter() in proxy_ftp.c.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+mod_proxy changes for httpd 2.0.17
+
+ *) Major rework of ap_proxy_ftp_handler() to use filters (begone foul
+ BUFF!!!). It compiles, but is untested, and the build environment needs
+ to be fixed to include proxy_ftp.c.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Cleanup of dead functions within proxy_util.c.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Reworked the storage of the client socket between keepalive connections
+ to fix some nasty problems with the socket lasting longer than the
+ memory pool it was allocated from.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fixed bug where a hostname without a "." in it (such as "localhost")
+ would not trigger an IP address check with ProxyBlock.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+mod_proxy changes for httpd 2.0.16
+
+ *) Fixed ProxyBlock bugs with ap_proxy_http_handler() and
+ ap_proxy_connect_handler().
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Updated ap_proxy_connect_handler() to support APR, while
+ moving some common code between http_handler and connect_handler
+ to proxy_util.c.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Updated mod_proxy.html docs to include v2.0 configuration.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fixed problem where responses without entity bodies would cause
+ the directly following proxy keepalive request to fail.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+mod_proxy changes for httpd 2.0.15
+
+ *) Added support for downstream keepalives in mod_proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Changed mod_proxy ap_proxy_http_handler() to support APR properly.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fix problem where incoming response headers were not being returned
+ to the client in mod_proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Added X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Server to
+ reverse proxied request headers in mod_proxy.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) replace INADDR_NONE with APR_INADDR_NONE [Ian Holsman <IanH@cnet.com>]
+
+ *) Fix problem with proxy configuration where globally set
+ configuration options were overridden inside virtual hosts.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Fix ProxyReceiveBufferSize where default value was left
+ uninitialised.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+ *) Some small changes:
+ - Ensured hop-by-hop headers were stripped as per
+ RFC2616 13.5.1.
+ - Upgraded version code to HTTP/1.1.
+ - Added Connection: close until Keepalives come.
+ - Some cosmetic fixes and commenting.
+ [Graham Leggett <minfrin@sharp.fm>]
+
+mod_proxy changes for httpd 2.0.14
+
+ *) removed ProxyNoCache and ProxyCacheForceCompletion config directives,
+ since we no longer directly cache from this module
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) removed cache
+ [Chuck Murcko <chuck@topsail.org>]
+
+ *) initial rerebuild for 2.0
+ [Chuck Murcko <chuck@topsail.org>]
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/Makefile b/rubbos/app/httpd-2.0.64/modules/proxy/Makefile
new file mode 100644
index 00000000..d1597bdf
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/Makefile
@@ -0,0 +1,8 @@
+top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64
+top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64
+srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/proxy
+builddir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/proxy
+VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/modules/proxy
+# a modules Makefile has no explicit targets -- they will be defined by
+# whatever modules are enabled. just grab special.mk to deal with this.
+include $(top_srcdir)/build/special.mk
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/Makefile.in b/rubbos/app/httpd-2.0.64/modules/proxy/Makefile.in
new file mode 100644
index 00000000..7c5c149d
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/Makefile.in
@@ -0,0 +1,3 @@
+# a modules Makefile has no explicit targets -- they will be defined by
+# whatever modules are enabled. just grab special.mk to deal with this.
+include $(top_srcdir)/build/special.mk
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUmakefile b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUmakefile
new file mode 100644
index 00000000..61842f0a
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUmakefile
@@ -0,0 +1,247 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)\build\NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME =
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION =
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME =
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE =
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/proxy.nlm \
+ $(OBJDIR)/proxycon.nlm \
+ $(OBJDIR)/proxyftp.nlm \
+ $(OBJDIR)/proxyhtp.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ copy $(OBJDIR)\*.nlm $(INSTALL)\Apache2\modules\*.*
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxy b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxy
new file mode 100644
index 00000000..d6abf6b3
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxy
@@ -0,0 +1,261 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = proxy
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Proxy Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Proxy Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM = _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM = _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/proxy.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/mod_proxy.o \
+ $(OBJDIR)/proxy_util.o \
+ $(OBJDIR)/libprews.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ libcpre.o \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @$(APR)/aprlib.imp \
+ @$(NWOS)/httpd.imp \
+ @libc.imp \
+ @ws2nlm.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ proxy_module \
+ proxy_hook_scheme_handler \
+ proxy_hook_canon_handler \
+ ap_proxy_ssl_enable \
+ ap_proxy_ssl_disable \
+ proxy_run_fixups \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+$(OBJDIR)/%.o: ../arch/netware/%.c $(OBJDIR)\$(NLM_NAME)_cc.opt
+ @echo compiling $<
+ $(CC) $< -o=$(OBJDIR)\$(@F) @$(OBJDIR)\$(NLM_NAME)_cc.opt
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxycon b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxycon
new file mode 100644
index 00000000..07c91f70
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxycon
@@ -0,0 +1,254 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = proxycon
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Proxy Connection Sub-Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Proxy Conn Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM = _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM = _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/proxycon.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/proxy_connect.o \
+ $(OBJDIR)/proxy_util.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ libcpre.o \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ proxy \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @$(APR)/aprlib.imp \
+ @$(NWOS)/httpd.imp \
+ @libc.imp \
+ proxy_module \
+ proxy_hook_scheme_handler \
+ proxy_hook_canon_handler \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ proxy_connect_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyftp b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyftp
new file mode 100644
index 00000000..bd5d527c
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyftp
@@ -0,0 +1,260 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = proxyftp
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Proxy FTP Sub-Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Proxy FTP Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM = _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM = _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/proxyftp.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/proxy_ftp.o \
+ $(OBJDIR)/proxy_util.o \
+ $(OBJDIR)/libprews.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ libcpre.o \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ proxy \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @$(APR)/aprlib.imp \
+ @$(NWOS)/httpd.imp \
+ @libc.imp \
+ @ws2nlm.imp \
+ proxy_module \
+ proxy_hook_scheme_handler \
+ proxy_hook_canon_handler \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ proxy_ftp_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+$(OBJDIR)/%.o: ../arch/netware/%.c $(OBJDIR)\$(NLM_NAME)_cc.opt
+ @echo compiling $<
+ $(CC) $< -o=$(OBJDIR)\$(@F) @$(OBJDIR)\$(NLM_NAME)_cc.opt
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyhtp b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyhtp
new file mode 100644
index 00000000..5fda2693
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/NWGNUproxyhtp
@@ -0,0 +1,263 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APRUTIL)/include \
+ $(AP_WORK)/include \
+ $(AP_WORK)/modules/http \
+ $(NWOS) \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = proxyhtp
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = Apache $(VERSION_STR) Proxy HTTP Sub-Module
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = Proxy HTTP Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM = _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM = _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/proxyhtp.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(OBJDIR)/proxy_http.o \
+ $(OBJDIR)/proxy_util.o \
+ $(OBJDIR)/libprews.o \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ libcpre.o \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ libc \
+ proxy \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @$(APR)/aprlib.imp \
+ @$(NWOS)/httpd.imp \
+ @libc.imp \
+ @ws2nlm.imp \
+ proxy_module \
+ proxy_hook_scheme_handler \
+ proxy_hook_canon_handler \
+ proxy_run_fixups \
+ ap_proxy_ssl_enable \
+ ap_proxy_ssl_disable \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ proxy_http_module \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+$(OBJDIR)/%.o: ../arch/netware/%.c $(OBJDIR)\$(NLM_NAME)_cc.opt
+ @echo compiling $<
+ $(CC) $< -o=$(OBJDIR)\$(@F) @$(OBJDIR)\$(NLM_NAME)_cc.opt
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/config.m4 b/rubbos/app/httpd-2.0.64/modules/proxy/config.m4
new file mode 100644
index 00000000..d33683e9
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/config.m4
@@ -0,0 +1,34 @@
+dnl modules enabled in this directory by default
+
+APACHE_MODPATH_INIT(proxy)
+
+if test "$enable_proxy" = "shared"; then
+ proxy_mods_enable=shared
+elif test "$enable_proxy" = "yes"; then
+ proxy_mods_enable=yes
+else
+ proxy_mods_enable=no
+fi
+
+proxy_objs="mod_proxy.lo proxy_util.lo"
+APACHE_MODULE(proxy, Apache proxy module, $proxy_objs, , $proxy_mods_enable)
+
+proxy_connect_objs="proxy_connect.lo"
+proxy_ftp_objs="proxy_ftp.lo"
+proxy_http_objs="proxy_http.lo"
+
+case "$host" in
+ *os2*)
+ # OS/2 DLLs must resolve all symbols at build time and
+ # these sub-modules need some from the main proxy module
+ proxy_connect_objs="$proxy_connect_objs mod_proxy.la"
+ proxy_ftp_objs="$proxy_ftp_objs mod_proxy.la"
+ proxy_http_objs="$proxy_http_objs mod_proxy.la"
+ ;;
+esac
+
+APACHE_MODULE(proxy_connect, Apache proxy CONNECT module, $proxy_connect_objs, , $proxy_mods_enable)
+APACHE_MODULE(proxy_ftp, Apache proxy FTP module, $proxy_ftp_objs, , $proxy_mods_enable)
+APACHE_MODULE(proxy_http, Apache proxy HTTP module, $proxy_http_objs, , $proxy_mods_enable)
+
+APACHE_MODPATH_FINISH
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/libproxy.exp b/rubbos/app/httpd-2.0.64/modules/proxy/libproxy.exp
new file mode 100644
index 00000000..a20f2378
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/libproxy.exp
@@ -0,0 +1 @@
+proxy_module
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.c b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.c
new file mode 100644
index 00000000..84d5fb10
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.c
@@ -0,0 +1,1181 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_proxy.h"
+#include "mod_core.h"
+
+#include "apr_optional.h"
+
+#ifndef MAX
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#endif
+
+/*
+ * A Web proxy module. Stages:
+ *
+ * translate_name: set filename to proxy:<URL>
+ * map_to_storage: run proxy_walk (rather than directory_walk/file_walk)
+ * can't trust directory_walk/file_walk since these are
+ * not in our filesystem. Prevents mod_http from serving
+ * the TRACE request we will set aside to handle later.
+ * type_checker: set type to PROXY_MAGIC_TYPE if filename begins proxy:
+ * fix_ups: convert the URL stored in the filename to the
+ * canonical form.
+ * handler: handle proxy requests
+ */
+
+/* -------------------------------------------------------------- */
+/* Translate the URL into a 'filename' */
+
+static int alias_match(const char *uri, const char *alias_fakename)
+{
+ const char *end_fakename = alias_fakename + strlen(alias_fakename);
+ const char *aliasp = alias_fakename, *urip = uri;
+
+ while (aliasp < end_fakename) {
+ if (*aliasp == '/') {
+ /* any number of '/' in the alias matches any number in
+ * the supplied URI, but there must be at least one...
+ */
+ if (*urip != '/')
+ return 0;
+
+ while (*aliasp == '/')
+ ++aliasp;
+ while (*urip == '/')
+ ++urip;
+ }
+ else {
+ /* Other characters are compared literally */
+ if (*urip++ != *aliasp++)
+ return 0;
+ }
+ }
+
+ /* Check last alias path component matched all the way */
+
+ if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
+ return 0;
+
+ /* Return number of characters from URI which matched (may be
+ * greater than length of alias, since we may have matched
+ * doubled slashes)
+ */
+
+ return urip - uri;
+}
+
+/* Detect if an absoluteURI should be proxied or not. Note that we
+ * have to do this during this phase because later phases are
+ * "short-circuiting"... i.e. translate_names will end when the first
+ * module returns OK. So for example, if the request is something like:
+ *
+ * GET http://othervhost/cgi-bin/printenv HTTP/1.0
+ *
+ * mod_alias will notice the /cgi-bin part and ScriptAlias it and
+ * short-circuit the proxy... just because of the ordering in the
+ * configuration file.
+ */
+static int proxy_detect(request_rec *r)
+{
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf;
+
+ conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+
+ /* Ick... msvc (perhaps others) promotes ternary short results to int */
+
+ if (conf->req && r->parsed_uri.scheme) {
+ /* but it might be something vhosted */
+ if (!(r->parsed_uri.hostname
+ && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
+ && ap_matches_request_vhost(r, r->parsed_uri.hostname,
+ (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
+ : ap_default_port(r))))) {
+ r->proxyreq = PROXYREQ_PROXY;
+ r->uri = r->unparsed_uri;
+ r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
+ r->handler = "proxy-server";
+ }
+ }
+ /* We need special treatment for CONNECT proxying: it has no scheme part */
+ else if (conf->req && r->method_number == M_CONNECT
+ && r->parsed_uri.hostname
+ && r->parsed_uri.port_str) {
+ r->proxyreq = PROXYREQ_PROXY;
+ r->uri = r->unparsed_uri;
+ r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
+ r->handler = "proxy-server";
+ }
+ return DECLINED;
+}
+
+static int proxy_trans(request_rec *r)
+{
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf =
+ (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+ int i, len;
+ struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
+
+ if (r->proxyreq) {
+ /* someone has already set up the proxy, it was possibly ourselves
+ * in proxy_detect
+ */
+ return OK;
+ }
+
+ /* XXX: since r->uri has been manipulated already we're not really
+ * compliant with RFC1945 at this point. But this probably isn't
+ * an issue because this is a hybrid proxy/origin server.
+ */
+
+ for (i = 0; i < conf->aliases->nelts; i++) {
+ len = alias_match(r->uri, ent[i].fake);
+
+ if (len > 0) {
+ if ((ent[i].real[0] == '!' ) && ( ent[i].real[1] == 0 )) {
+ return DECLINED;
+ }
+
+ r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
+ (r->uri + len ), NULL);
+ r->handler = "proxy-server";
+ r->proxyreq = PROXYREQ_REVERSE;
+ return OK;
+ }
+ }
+ return DECLINED;
+}
+
+static int proxy_walk(request_rec *r)
+{
+ proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,
+ &proxy_module);
+ ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;
+ ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;
+ ap_conf_vector_t *entry_config;
+ proxy_dir_conf *entry_proxy;
+ int num_sec = sconf->sec_proxy->nelts;
+ /* XXX: shouldn't we use URI here? Canonicalize it first?
+ * Pass over "proxy:" prefix
+ */
+ const char *proxyname = r->filename + 6;
+ int j;
+
+ for (j = 0; j < num_sec; ++j)
+ {
+ entry_config = sec_proxy[j];
+ entry_proxy = ap_get_module_config(entry_config, &proxy_module);
+
+ /* XXX: What about case insensitive matching ???
+ * Compare regex, fnmatch or string as appropriate
+ * If the entry doesn't relate, then continue
+ */
+ if (entry_proxy->r
+ ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0)
+ : (entry_proxy->p_is_fnmatch
+ ? apr_fnmatch(entry_proxy->p, proxyname, 0)
+ : strncmp(proxyname, entry_proxy->p,
+ strlen(entry_proxy->p)))) {
+ continue;
+ }
+ per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,
+ entry_config);
+ }
+
+ r->per_dir_config = per_dir_defaults;
+
+ return OK;
+}
+
+static int proxy_map_location(request_rec *r)
+{
+ int access_status;
+
+ if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+ return DECLINED;
+
+ /* Don't let the core or mod_http map_to_storage hooks handle this,
+ * We don't need directory/file_walk, and we want to TRACE on our own.
+ */
+ if ((access_status = proxy_walk(r))) {
+ ap_die(access_status, r);
+ return access_status;
+ }
+
+ return OK;
+}
+
+/* -------------------------------------------------------------- */
+/* Fixup the filename */
+
+/*
+ * Canonicalise the URL
+ */
+static int proxy_fixup(request_rec *r)
+{
+ char *url, *p;
+ int access_status;
+
+ if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+ return DECLINED;
+
+ /* XXX: Shouldn't we try this before we run the proxy_walk? */
+ url = &r->filename[6];
+
+ /* canonicalise each specific scheme */
+ if ((access_status = proxy_run_canon_handler(r, url))) {
+ return access_status;
+ }
+
+ p = strchr(url, ':');
+ if (p == NULL || p == url)
+ return HTTP_BAD_REQUEST;
+
+ return OK; /* otherwise; we've done the best we can */
+}
+
+/* Send a redirection if the request contains a hostname which is not */
+/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
+/* servers like Netscape's allow this and access hosts from the local */
+/* domain in this case. I think it is better to redirect to a FQDN, since */
+/* these will later be found in the bookmarks files. */
+/* The "ProxyDomain" directive determines what domain will be appended */
+static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
+{
+ char *nuri;
+ const char *ref;
+
+ /* We only want to worry about GETs */
+ if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
+ return DECLINED;
+
+ /* If host does contain a dot already, or it is "localhost", decline */
+ if (strchr(r->parsed_uri.hostname, '.') != NULL
+ || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
+ return DECLINED; /* host name has a dot already */
+
+ ref = apr_table_get(r->headers_in, "Referer");
+
+ /* Reassemble the request, but insert the domain after the host name */
+ /* Note that the domain name always starts with a dot */
+ r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,
+ domain, NULL);
+ nuri = apr_uri_unparse(r->pool,
+ &r->parsed_uri,
+ APR_URI_UNP_REVEALPASSWORD);
+
+ apr_table_set(r->headers_out, "Location", nuri);
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Domain missing: %s sent to %s%s%s", r->uri,
+ apr_uri_unparse(r->pool, &r->parsed_uri,
+ APR_URI_UNP_OMITUSERINFO),
+ ref ? " from " : "", ref ? ref : "");
+
+ return HTTP_MOVED_PERMANENTLY;
+}
+
+/* -------------------------------------------------------------- */
+/* Invoke handler */
+
+static int proxy_handler(request_rec *r)
+{
+ char *url, *scheme, *p;
+ const char *p2;
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf = (proxy_server_conf *)
+ ap_get_module_config(sconf, &proxy_module);
+ apr_array_header_t *proxies = conf->proxies;
+ struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
+ int i, rc, access_status;
+ int direct_connect = 0;
+ const char *str;
+ long maxfwd;
+
+ /* is this for us? */
+ if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+ return DECLINED;
+
+ /* handle max-forwards / OPTIONS / TRACE */
+ if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) {
+ maxfwd = strtol(str, NULL, 10);
+ if (maxfwd < 1) {
+ switch (r->method_number) {
+ case M_TRACE: {
+ int access_status;
+ r->proxyreq = PROXYREQ_NONE;
+ if ((access_status = ap_send_http_trace(r)))
+ ap_die(access_status, r);
+ else
+ ap_finalize_request_protocol(r);
+ return OK;
+ }
+ case M_OPTIONS: {
+ int access_status;
+ r->proxyreq = PROXYREQ_NONE;
+ if ((access_status = ap_send_http_options(r)))
+ ap_die(access_status, r);
+ else
+ ap_finalize_request_protocol(r);
+ return OK;
+ }
+ default: {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Max-Forwards has reached zero - proxy loop?");
+ }
+ }
+ }
+ maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0;
+ }
+ else {
+ /* set configured max-forwards */
+ maxfwd = conf->maxfwd;
+ }
+ apr_table_set(r->headers_in, "Max-Forwards",
+ apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
+
+ if (r->method_number == M_TRACE) {
+ core_server_config *coreconf = (core_server_config *)
+ ap_get_module_config(sconf, &core_module);
+
+ if (coreconf->trace_enable == AP_TRACE_DISABLE)
+ {
+ /* Allow "error-notes" string to be printed by ap_send_error_response()
+ * Note; this goes nowhere, canned error response need an overhaul.
+ */
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE forbidden by server configuration");
+ apr_table_setn(r->notes, "verbose-error-to", "*");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: TRACE forbidden by server configuration");
+ return HTTP_FORBIDDEN;
+ }
+
+ /* Can't test ap_should_client_block, we aren't ready to send
+ * the client a 100 Continue response till the connection has
+ * been established
+ */
+ if (coreconf->trace_enable != AP_TRACE_EXTENDED
+ && (r->read_length || r->read_chunked || r->remaining))
+ {
+ /* Allow "error-notes" string to be printed by ap_send_error_response()
+ * Note; this goes nowhere, canned error response need an overhaul.
+ */
+ apr_table_setn(r->notes, "error-notes",
+ "TRACE with request body is not allowed");
+ apr_table_setn(r->notes, "verbose-error-to", "*");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: TRACE with request body is not allowed");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ }
+
+ url = r->filename + 6;
+ p = strchr(url, ':');
+ if (p == NULL)
+ return HTTP_BAD_REQUEST;
+
+ /* If the host doesn't have a domain name, add one and redirect. */
+ if (conf->domain != NULL) {
+ rc = proxy_needsdomain(r, url, conf->domain);
+ if (ap_is_HTTP_REDIRECT(rc))
+ return HTTP_MOVED_PERMANENTLY;
+ }
+
+ *p = '\0';
+ scheme = apr_pstrdup(r->pool, url);
+ *p = ':';
+
+ /* Check URI's destination host against NoProxy hosts */
+ /* Bypass ProxyRemote server lookup if configured as NoProxy */
+ /* we only know how to handle communication to a proxy via http */
+ /*if (strcasecmp(scheme, "http") == 0) */
+ {
+ int ii;
+ struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+
+ for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
+ direct_connect = list[ii].matcher(&list[ii], r);
+ }
+#if DEBUGGING
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
+ r->uri);
+#endif
+ }
+
+ /* firstly, try a proxy, unless a NoProxy directive is active */
+ if (!direct_connect) {
+ for (i = 0; i < proxies->nelts; i++) {
+ p2 = ap_strchr_c(ents[i].scheme, ':'); /* is it a partial URL? */
+ if (strcmp(ents[i].scheme, "*") == 0 ||
+ (ents[i].use_regex &&
+ ap_regexec(ents[i].regexp, url, 0,NULL, 0) == 0) ||
+ (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
+ (p2 != NULL &&
+ strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
+
+ /* handle the scheme */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "Trying to run scheme_handler against proxy");
+ access_status = proxy_run_scheme_handler(r, conf, url, ents[i].hostname, ents[i].port);
+
+ /* an error or success */
+ if (access_status != DECLINED && access_status != HTTP_BAD_GATEWAY) {
+ return access_status;
+ }
+ /* we failed to talk to the upstream proxy */
+ }
+ }
+ }
+
+ /* otherwise, try it direct */
+ /* N.B. what if we're behind a firewall, where we must use a proxy or
+ * give up??
+ */
+
+ /* handle the scheme */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "Trying to run scheme_handler");
+ access_status = proxy_run_scheme_handler(r, conf, url, NULL, 0);
+ if (DECLINED == access_status) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: No protocol handler was valid for the URL %s. "
+ "If you are using a DSO version of mod_proxy, make sure "
+ "the proxy submodules are included in the configuration "
+ "using LoadModule.", r->uri);
+ return HTTP_FORBIDDEN;
+ }
+ return access_status;
+}
+
+/* -------------------------------------------------------------- */
+/* Setup configurable data */
+
+static void * create_proxy_config(apr_pool_t *p, server_rec *s)
+{
+ proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
+
+ ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *));
+ ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
+ ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ ps->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+ ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
+ ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
+ ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
+ ps->domain = NULL;
+ ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
+ ps->viaopt_set = 0; /* 0 means default */
+ ps->req = 0;
+ ps->req_set = 0;
+ ps->recv_buffer_size = 0; /* this default was left unset for some reason */
+ ps->recv_buffer_size_set = 0;
+ ps->io_buffer_size = AP_IOBUFSIZE;
+ ps->io_buffer_size_set = 0;
+ ps->maxfwd = DEFAULT_MAX_FORWARDS;
+ ps->maxfwd_set = 0;
+ ps->error_override = 0;
+ ps->error_override_set = 0;
+ ps->preserve_host_set = 0;
+ ps->preserve_host = 0;
+ ps->timeout = 0;
+ ps->timeout_set = 0;
+ ps->badopt = bad_error;
+ ps->badopt_set = 0;
+ return ps;
+}
+
+static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
+ proxy_server_conf *base = (proxy_server_conf *) basev;
+ proxy_server_conf *overrides = (proxy_server_conf *) overridesv;
+
+ ps->proxies = apr_array_append(p, base->proxies, overrides->proxies);
+ ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
+ ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
+ ps->raliases = apr_array_append(p, base->raliases, overrides->raliases);
+ ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
+ ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
+ ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
+
+ ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
+ ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
+ ps->viaopt_set = overrides->viaopt_set || base->viaopt_set;
+ ps->req = (overrides->req_set == 0) ? base->req : overrides->req;
+ ps->req_set = overrides->req_set || base->req_set;
+ ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? base->recv_buffer_size : overrides->recv_buffer_size;
+ ps->recv_buffer_size_set = overrides->recv_buffer_size_set || base->recv_buffer_size_set;
+ ps->io_buffer_size = (overrides->io_buffer_size_set == 0) ? base->io_buffer_size : overrides->io_buffer_size;
+ ps->io_buffer_size_set = overrides->io_buffer_size_set || base->io_buffer_size_set;
+ ps->maxfwd = (overrides->maxfwd_set == 0) ? base->maxfwd : overrides->maxfwd;
+ ps->maxfwd_set = overrides->maxfwd_set || base->maxfwd_set;
+ ps->error_override = (overrides->error_override_set == 0) ? base->error_override : overrides->error_override;
+ ps->error_override_set = overrides->error_override_set || base->error_override_set;
+ ps->preserve_host = (overrides->preserve_host_set == 0) ? base->preserve_host : overrides->preserve_host;
+ ps->preserve_host_set = overrides->preserve_host_set || base->preserve_host_set;
+ ps->timeout= (overrides->timeout_set == 0) ? base->timeout : overrides->timeout;
+ ps->timeout_set = overrides->timeout_set || base->timeout_set;
+ ps->badopt = (overrides->badopt_set == 0) ? base->badopt : overrides->badopt;
+ ps->badopt_set = overrides->badopt_set || base->badopt_set;
+
+ return ps;
+}
+
+static void *create_proxy_dir_config(apr_pool_t *p, char *dummy)
+{
+ proxy_dir_conf *new =
+ (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
+
+ /* Filled in by proxysection, when applicable */
+
+ return (void *) new;
+}
+
+static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
+{
+ proxy_dir_conf *new = (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
+ proxy_dir_conf *add = (proxy_dir_conf *) addv;
+ proxy_dir_conf *base = (proxy_dir_conf *) basev;
+
+ new->p = add->p;
+ new->p_is_fnmatch = add->p_is_fnmatch;
+ new->r = add->r;
+ new->ftp_directory_charset = add->ftp_directory_charset ?
+ add->ftp_directory_charset :
+ base->ftp_directory_charset;
+ return new;
+}
+
+
+static const char *
+ add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf =
+ (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+ struct proxy_remote *new;
+ char *p, *q;
+ char *r, *f, *scheme;
+ regex_t *reg = NULL;
+ int port;
+
+ r = apr_pstrdup(cmd->pool, r1);
+ scheme = apr_pstrdup(cmd->pool, r1);
+ f = apr_pstrdup(cmd->pool, f1);
+ p = strchr(r, ':');
+ if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0') {
+ if (regex)
+ return "ProxyRemoteMatch: Bad syntax for a remote proxy server";
+ else
+ return "ProxyRemote: Bad syntax for a remote proxy server";
+ }
+ else {
+ scheme[p-r] = 0;
+ }
+ q = strchr(p + 3, ':');
+ if (q != NULL) {
+ if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
+ if (regex)
+ return "ProxyRemoteMatch: Bad syntax for a remote proxy server (bad port number)";
+ else
+ return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
+ }
+ *q = '\0';
+ }
+ else
+ port = -1;
+ *p = '\0';
+ if (regex) {
+ reg = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
+ if (!reg)
+ return "Regular expression for ProxyRemoteMatch could not be compiled.";
+ }
+ else
+ if (strchr(f, ':') == NULL)
+ ap_str_tolower(f); /* lowercase scheme */
+ ap_str_tolower(p + 3); /* lowercase hostname */
+
+ if (port == -1) {
+ port = apr_uri_port_of_scheme(scheme);
+ }
+
+ new = apr_array_push(conf->proxies);
+ new->scheme = f;
+ new->protocol = r;
+ new->hostname = p + 3;
+ new->port = port;
+ new->regexp = reg;
+ new->use_regex = regex;
+ return NULL;
+}
+
+static const char *
+ add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+{
+ return add_proxy(cmd, dummy, f1, r1, 0);
+}
+
+static const char *
+ add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+{
+ return add_proxy(cmd, dummy, f1, r1, 1);
+}
+
+static const char *
+ add_pass(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf =
+ (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+ struct proxy_alias *new;
+ if (r!=NULL && cmd->path == NULL ) {
+ new = apr_array_push(conf->aliases);
+ new->fake = f;
+ new->real = r;
+ } else if (r==NULL && cmd->path != NULL) {
+ new = apr_array_push(conf->aliases);
+ new->fake = cmd->path;
+ new->real = f;
+ } else {
+ if ( r== NULL)
+ return "ProxyPass needs a path when not defined in a location";
+ else
+ return "ProxyPass can not have a path when defined in a location";
+ }
+
+ return NULL;
+}
+
+static const char *
+ add_pass_reverse(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+ server_rec *s = cmd->server;
+ proxy_server_conf *conf;
+ struct proxy_alias *new;
+
+ conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
+ &proxy_module);
+ if (r!=NULL && cmd->path == NULL ) {
+ new = apr_array_push(conf->raliases);
+ new->fake = f;
+ new->real = r;
+ } else if (r==NULL && cmd->path != NULL) {
+ new = apr_array_push(conf->raliases);
+ new->fake = cmd->path;
+ new->real = f;
+ } else {
+ if ( r == NULL)
+ return "ProxyPassReverse needs a path when not defined in a location";
+ else
+ return "ProxyPassReverse can not have a path when defined in a location";
+ }
+
+ return NULL;
+}
+
+static const char *
+ set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
+{
+ server_rec *s = parms->server;
+ proxy_server_conf *conf =
+ ap_get_module_config(s->module_config, &proxy_module);
+ struct noproxy_entry *new;
+ struct noproxy_entry *list = (struct noproxy_entry *) conf->noproxies->elts;
+ struct apr_sockaddr_t *addr;
+ int found = 0;
+ int i;
+
+ /* Don't duplicate entries */
+ for (i = 0; i < conf->noproxies->nelts; i++) {
+ if (apr_strnatcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */
+ found = 1;
+ }
+ }
+
+ if (!found) {
+ new = apr_array_push(conf->noproxies);
+ new->name = arg;
+ if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
+ new->addr = addr;
+ }
+ else {
+ new->addr = NULL;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Set the ports CONNECT can use
+ */
+static const char *
+ set_allowed_ports(cmd_parms *parms, void *dummy, const char *arg)
+{
+ server_rec *s = parms->server;
+ proxy_server_conf *conf =
+ ap_get_module_config(s->module_config, &proxy_module);
+ int *New;
+
+ if (!apr_isdigit(arg[0]))
+ return "AllowCONNECT: port number must be numeric";
+
+ New = apr_array_push(conf->allowed_connect_ports);
+ *New = atoi(arg);
+ return NULL;
+}
+
+/* Similar to set_proxy_exclude(), but defining directly connected hosts,
+ * which should never be accessed via the configured ProxyRemote servers
+ */
+static const char *
+ set_proxy_dirconn(cmd_parms *parms, void *dummy, const char *arg)
+{
+ server_rec *s = parms->server;
+ proxy_server_conf *conf =
+ ap_get_module_config(s->module_config, &proxy_module);
+ struct dirconn_entry *New;
+ struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+ int found = 0;
+ int i;
+
+ /* Don't duplicate entries */
+ for (i = 0; i < conf->dirconn->nelts; i++) {
+ if (strcasecmp(arg, list[i].name) == 0)
+ found = 1;
+ }
+
+ if (!found) {
+ New = apr_array_push(conf->dirconn);
+ New->name = apr_pstrdup(parms->pool, arg);
+ New->hostaddr = NULL;
+
+ if (ap_proxy_is_ipaddr(New, parms->pool)) {
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed addr %s", inet_ntoa(New->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed mask %s", inet_ntoa(New->mask));
+#endif
+ }
+ else if (ap_proxy_is_domainname(New, parms->pool)) {
+ ap_str_tolower(New->name);
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed domain %s", New->name);
+#endif
+ }
+ else if (ap_proxy_is_hostname(New, parms->pool)) {
+ ap_str_tolower(New->name);
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Parsed host %s", New->name);
+#endif
+ }
+ else {
+ ap_proxy_is_word(New, parms->pool);
+#if DEBUGGING
+ fprintf(stderr, "Parsed word %s\n", New->name);
+#endif
+ }
+ }
+ return NULL;
+}
+
+static const char *
+ set_proxy_domain(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ if (arg[0] != '.')
+ return "ProxyDomain: domain name must start with a dot.";
+
+ psf->domain = arg;
+ return NULL;
+}
+
+static const char *
+ set_proxy_req(cmd_parms *parms, void *dummy, int flag)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ psf->req = flag;
+ psf->req_set = 1;
+ return NULL;
+}
+static const char *
+ set_proxy_error_override(cmd_parms *parms, void *dummy, int flag)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ psf->error_override = flag;
+ psf->error_override_set = 1;
+ return NULL;
+}
+static const char *
+ set_preserve_host(cmd_parms *parms, void *dummy, int flag)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ psf->preserve_host = flag;
+ psf->preserve_host_set = 1;
+ return NULL;
+}
+
+static const char *
+ set_recv_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+ int s = atoi(arg);
+ if (s < 512 && s != 0) {
+ return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
+ }
+
+ psf->recv_buffer_size = s;
+ psf->recv_buffer_size_set = 1;
+ return NULL;
+}
+
+static const char *
+ set_io_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+ long s = atol(arg);
+
+ psf->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
+ psf->io_buffer_size_set = 1;
+ return NULL;
+}
+
+static const char *
+ set_max_forwards(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+ long s = atol(arg);
+ if (s < 0) {
+ return "ProxyMaxForwards must be greater or equal to zero..";
+ }
+
+ psf->maxfwd = s;
+ psf->maxfwd_set = 1;
+ return NULL;
+}
+static const char*
+ set_proxy_timeout(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+ int timeout;
+
+ timeout=atoi(arg);
+ if (timeout<1) {
+ return "Proxy Timeout must be at least 1 second.";
+ }
+ psf->timeout_set=1;
+ psf->timeout=apr_time_from_sec(timeout);
+
+ return NULL;
+}
+
+static const char*
+ set_via_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ if (strcasecmp(arg, "Off") == 0)
+ psf->viaopt = via_off;
+ else if (strcasecmp(arg, "On") == 0)
+ psf->viaopt = via_on;
+ else if (strcasecmp(arg, "Block") == 0)
+ psf->viaopt = via_block;
+ else if (strcasecmp(arg, "Full") == 0)
+ psf->viaopt = via_full;
+ else {
+ return "ProxyVia must be one of: "
+ "off | on | full | block";
+ }
+
+ psf->viaopt_set = 1;
+ return NULL;
+}
+
+static const char*
+ set_bad_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+ proxy_server_conf *psf =
+ ap_get_module_config(parms->server->module_config, &proxy_module);
+
+ if (strcasecmp(arg, "IsError") == 0)
+ psf->badopt = bad_error;
+ else if (strcasecmp(arg, "Ignore") == 0)
+ psf->badopt = bad_ignore;
+ else if (strcasecmp(arg, "StartBody") == 0)
+ psf->badopt = bad_body;
+ else {
+ return "ProxyBadHeader must be one of: "
+ "IsError | Ignore | StartBody";
+ }
+
+ psf->badopt_set = 1;
+ return NULL;
+}
+
+static const char* set_ftp_directory_charset(cmd_parms *cmd, void *dconf,
+ const char *arg)
+{
+ proxy_dir_conf *conf = dconf;
+
+ conf->ftp_directory_charset = arg;
+ return NULL;
+}
+
+static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
+{
+ proxy_server_conf *sconf = ap_get_module_config(s->module_config,
+ &proxy_module);
+ void **new_space = (void **)apr_array_push(sconf->sec_proxy);
+
+ *new_space = dir_config;
+}
+
+static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+ const char *errmsg;
+ const char *endp = ap_strrchr_c(arg, '>');
+ int old_overrides = cmd->override;
+ char *old_path = cmd->path;
+ proxy_dir_conf *conf;
+ ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
+ regex_t *r = NULL;
+ const command_rec *thiscmd = cmd->cmd;
+
+ const char *err = ap_check_cmd_context(cmd,
+ NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (endp == NULL) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "> directive missing closing '>'", NULL);
+ }
+
+ arg=apr_pstrndup(cmd->pool, arg, endp-arg);
+
+ if (!arg) {
+ if (thiscmd->cmd_data)
+ return "<ProxyMatch > block must specify a path";
+ else
+ return "<Proxy > block must specify a path";
+ }
+
+ cmd->path = ap_getword_conf(cmd->pool, &arg);
+ cmd->override = OR_ALL|ACCESS_CONF;
+
+ if (!strncasecmp(cmd->path, "proxy:", 6))
+ cmd->path += 6;
+
+ /* XXX Ignore case? What if we proxy a case-insensitive server?!?
+ * While we are at it, shouldn't we also canonicalize the entire
+ * scheme? See proxy_fixup()
+ */
+ if (thiscmd->cmd_data) { /* <ProxyMatch> */
+ r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+ if (!r) {
+ return "Regex could not be compiled";
+ }
+ }
+ else if (!strcmp(cmd->path, "~")) {
+ cmd->path = ap_getword_conf(cmd->pool, &arg);
+ if (!cmd->path)
+ return "<Proxy ~ > block must specify a path";
+ if (strncasecmp(cmd->path, "proxy:", 6))
+ cmd->path += 6;
+ r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+ if (!r) {
+ return "Regex could not be compiled";
+ }
+ }
+
+ /* initialize our config and fetch it */
+ conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
+ &proxy_module, cmd->pool);
+
+ errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
+ if (errmsg != NULL)
+ return errmsg;
+
+ conf->r = r;
+ conf->p = cmd->path;
+ conf->p_is_fnmatch = apr_fnmatch_test(conf->p);
+
+ ap_add_per_proxy_conf(cmd->server, new_dir_conf);
+
+ if (*arg != '\0') {
+ return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
+ "> arguments not (yet) supported.", NULL);
+ }
+
+ cmd->path = old_path;
+ cmd->override = old_overrides;
+
+ return NULL;
+}
+
+static const command_rec proxy_cmds[] =
+{
+ AP_INIT_RAW_ARGS("<Proxy", proxysection, NULL, RSRC_CONF,
+ "Container for directives affecting resources located in the proxied "
+ "location"),
+ AP_INIT_RAW_ARGS("<ProxyMatch", proxysection, (void*)1, RSRC_CONF,
+ "Container for directives affecting resources located in the proxied "
+ "location, in regular expression syntax"),
+ AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
+ "on if the true proxy requests should be accepted"),
+ AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
+ "a scheme, partial URL or '*' and a proxy server"),
+ AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
+ "a regex pattern and a proxy server"),
+ AP_INIT_TAKE12("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF,
+ "a virtual path and a URL"),
+ AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
+ "a virtual path and a URL for reverse proxy behaviour"),
+ AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
+ "A list of names, hosts or domains to which the proxy will not connect"),
+ AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
+ "Receive buffer size for outgoing HTTP and FTP connections in bytes"),
+ AP_INIT_TAKE1("ProxyIOBufferSize", set_io_buffer_size, NULL, RSRC_CONF,
+ "IO buffer size for outgoing HTTP and FTP connections in bytes"),
+ AP_INIT_TAKE1("ProxyMaxForwards", set_max_forwards, NULL, RSRC_CONF,
+ "The maximum number of proxies a request may be forwarded through."),
+ AP_INIT_ITERATE("NoProxy", set_proxy_dirconn, NULL, RSRC_CONF,
+ "A list of domains, hosts, or subnets to which the proxy will connect directly"),
+ AP_INIT_TAKE1("ProxyDomain", set_proxy_domain, NULL, RSRC_CONF,
+ "The default intranet domain name (in absence of a domain in the URL)"),
+ AP_INIT_ITERATE("AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF,
+ "A list of ports which CONNECT may connect to"),
+ AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF,
+ "Configure Via: proxy header header to one of: on | off | block | full"),
+ AP_INIT_FLAG("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF,
+ "use our error handling pages instead of the servers' we are proxying"),
+ AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF,
+ "on if we should preserve host header while proxying"),
+ AP_INIT_TAKE1("ProxyTimeout", set_proxy_timeout, NULL, RSRC_CONF,
+ "Set the timeout (in seconds) for a proxied connection. "
+ "This overrides the server timeout"),
+ AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
+ "How to handle bad header line in response: IsError | Ignore | StartBody"),
+ AP_INIT_TAKE1("ProxyFtpDirCharset", set_ftp_directory_charset, NULL,
+ RSRC_CONF|ACCESS_CONF, "Define the character set for proxied FTP listings"),
+ {NULL}
+};
+
+APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
+
+static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL;
+static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL;
+
+PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c)
+{
+ /*
+ * if c == NULL just check if the optional function was imported
+ * else run the optional function so ssl filters are inserted
+ */
+ if (proxy_ssl_enable) {
+ return c ? proxy_ssl_enable(c) : 1;
+ }
+
+ return 0;
+}
+
+PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c)
+{
+ if (proxy_ssl_disable) {
+ return proxy_ssl_disable(c);
+ }
+
+ return 0;
+}
+
+static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
+ proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
+
+ return OK;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+ /* fixup before mod_rewrite, so that the proxied url will not
+ * escaped accidentally by our fixup.
+ */
+ static const char * const aszSucc[]={ "mod_rewrite.c", NULL };
+
+ /* handler */
+ ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
+ /* filename-to-URI translation */
+ ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
+ /* walk <Proxy > entries and suppress default TRACE behavior */
+ ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
+ /* fixups */
+ ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
+ /* post read_request handling */
+ ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
+ /* post config handling */
+ ap_hook_post_config(proxy_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_module =
+{
+ STANDARD20_MODULE_STUFF,
+ create_proxy_dir_config, /* create per-directory config structure */
+ merge_proxy_dir_config, /* merge per-directory config structures */
+ create_proxy_config, /* create per-server config structure */
+ merge_proxy_config, /* merge per-server config structures */
+ proxy_cmds, /* command table */
+ register_hooks
+};
+
+APR_HOOK_STRUCT(
+ APR_HOOK_LINK(scheme_handler)
+ APR_HOOK_LINK(canon_handler)
+)
+
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler,
+ (request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyhost,
+ apr_port_t proxyport),(r,conf,url,
+ proxyhost,proxyport),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler,
+ (request_rec *r, char *url),(r,
+ url),DECLINED)
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
+ (request_rec *r), (r),
+ OK, DECLINED)
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.dsp b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.dsp
new file mode 100644
index 00000000..9fa9feb0
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.dsp
@@ -0,0 +1,140 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy.mak" CFG="mod_proxy - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_proxy - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "PROXY_DECLARE_EXPORT" /Fd"Release\mod_proxy_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so /opt:ref
+
+!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "PROXY_DECLARE_EXPORT" /Fd"Debug\mod_proxy_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy - Win32 Release"
+# Name "mod_proxy - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\mod_proxy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\proxy_util.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_proxy - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy.so "proxy_module for Apache" ../../include/ap_release.h > .\mod_proxy.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_proxy - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy.so "proxy_module for Apache" ../../include/ap_release.h > .\mod_proxy.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.h b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.h
new file mode 100644
index 00000000..d1ed7d46
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy.h
@@ -0,0 +1,255 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOD_PROXY_H
+#define MOD_PROXY_H
+
+/*
+ * Main include file for the Apache proxy
+ */
+
+/*
+
+ Also note numerous FIXMEs and CHECKMEs which should be eliminated.
+
+ This code is once again experimental!
+
+ Things to do:
+
+ 1. Make it completely work (for FTP too)
+
+ 2. HTTP/1.1
+
+ Chuck Murcko <chuck@topsail.org> 02-06-01
+
+ */
+
+#define CORE_PRIVATE
+
+#include "apr_hooks.h"
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_md5.h"
+#include "apr_network_io.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+#include "apr_date.h"
+#include "apr_fnmatch.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "ap_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "http_vhost.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_connection.h"
+#include "util_filter.h"
+#include "util_ebcdic.h"
+
+#if APR_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if APR_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+/* for proxy_canonenc() */
+enum enctype {
+ enc_path, enc_search, enc_user, enc_fpath, enc_parm
+};
+
+#if APR_CHARSET_EBCDIC
+#define CRLF "\r\n"
+#else /*APR_CHARSET_EBCDIC*/
+#define CRLF "\015\012"
+#endif /*APR_CHARSET_EBCDIC*/
+
+/* default Max-Forwards header setting */
+#define DEFAULT_MAX_FORWARDS 10
+
+/* static information about a remote proxy */
+struct proxy_remote {
+ const char *scheme; /* the schemes handled by this proxy, or '*' */
+ const char *protocol; /* the scheme used to talk to this proxy */
+ const char *hostname; /* the hostname of this proxy */
+ apr_port_t port; /* the port for this proxy */
+ regex_t *regexp; /* compiled regex (if any) for the remote */
+ int use_regex; /* simple boolean. True if we have a regex pattern */
+};
+
+struct proxy_alias {
+ const char *real;
+ const char *fake;
+};
+
+struct dirconn_entry {
+ char *name;
+ struct in_addr addr, mask;
+ struct apr_sockaddr_t *hostaddr;
+ int (*matcher) (struct dirconn_entry * This, request_rec *r);
+};
+
+struct noproxy_entry {
+ const char *name;
+ struct apr_sockaddr_t *addr;
+};
+
+typedef struct {
+ apr_array_header_t *proxies;
+ apr_array_header_t *sec_proxy;
+ apr_array_header_t *aliases;
+ apr_array_header_t *raliases;
+ apr_array_header_t *noproxies;
+ apr_array_header_t *dirconn;
+ apr_array_header_t *allowed_connect_ports;
+ const char *domain; /* domain name to use in absence of a domain name in the request */
+ int req; /* true if proxy requests are enabled */
+ char req_set;
+ enum {
+ via_off,
+ via_on,
+ via_block,
+ via_full
+ } viaopt; /* how to deal with proxy Via: headers */
+ char viaopt_set;
+ apr_size_t recv_buffer_size;
+ char recv_buffer_size_set;
+ apr_size_t io_buffer_size;
+ char io_buffer_size_set;
+ long maxfwd;
+ char maxfwd_set;
+ /**
+ * the following setting masks the error page
+ * returned from the 'proxied server' and just
+ * forwards the status code upwards.
+ * This allows the main server (us) to generate
+ * the error page, (so it will look like a error
+ * returned from the rest of the system
+ */
+ int error_override;
+ int error_override_set;
+ int preserve_host;
+ int preserve_host_set;
+ apr_interval_time_t timeout;
+ apr_interval_time_t timeout_set;
+ enum {
+ bad_error,
+ bad_ignore,
+ bad_body
+ } badopt; /* how to deal with bad headers */
+ char badopt_set;
+
+} proxy_server_conf;
+
+typedef struct {
+ const char *p; /* The path */
+ int p_is_fnmatch; /* Is this path an fnmatch candidate? */
+ regex_t *r; /* Is this a regex? */
+ const char *ftp_directory_charset;
+} proxy_dir_conf;
+
+typedef struct {
+ conn_rec *connection;
+ char *hostname;
+ apr_port_t port;
+ int is_ssl;
+} proxy_conn_rec;
+
+typedef struct {
+ float cache_completion; /* completion percentage */
+ int content_length; /* length of the content */
+} proxy_completion;
+
+
+/* hooks */
+
+/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and
+ * PROXY_DECLARE_DATA with appropriate export and import tags for the platform
+ */
+#if !defined(WIN32)
+#define PROXY_DECLARE(type) type
+#define PROXY_DECLARE_NONSTD(type) type
+#define PROXY_DECLARE_DATA
+#elif defined(PROXY_DECLARE_STATIC)
+#define PROXY_DECLARE(type) type __stdcall
+#define PROXY_DECLARE_NONSTD(type) type
+#define PROXY_DECLARE_DATA
+#elif defined(PROXY_DECLARE_EXPORT)
+#define PROXY_DECLARE(type) __declspec(dllexport) type __stdcall
+#define PROXY_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define PROXY_DECLARE_DATA __declspec(dllexport)
+#else
+#define PROXY_DECLARE(type) __declspec(dllimport) type __stdcall
+#define PROXY_DECLARE_NONSTD(type) __declspec(dllimport) type
+#define PROXY_DECLARE_DATA __declspec(dllimport)
+#endif
+
+/**
+ * Hook an optional proxy hook. Unlike static hooks, this uses a macro
+ * instead of a function.
+ */
+#define PROXY_OPTIONAL_HOOK(name,fn,pre,succ,order) \
+ APR_OPTIONAL_HOOK(proxy,name,fn,pre,succ,order)
+
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r,
+ proxy_server_conf *conf, char *url,
+ const char *proxyhost, apr_port_t proxyport))
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r,
+ char *url))
+
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr))
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r))
+
+/* proxy_util.c */
+
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r);
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x);
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
+ int isenc);
+PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
+ char **passwordp, char **hostp, apr_port_t *port);
+PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x);
+PROXY_DECLARE(apr_table_t *)ap_proxy_read_headers(request_rec *r, request_rec *rp, char *buffer, int size, conn_rec *c);
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val);
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val);
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x);
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y);
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message);
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r);
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key);
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);
+PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);
+PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
+
+/* For proxy_util */
+extern module AP_MODULE_DECLARE_DATA proxy_module;
+
+#endif /*MOD_PROXY_H*/
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_connect.dsp b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_connect.dsp
new file mode 100644
index 00000000..0c2a12b0
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_connect.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_connect" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_connect - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_connect.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_connect.mak" CFG="mod_proxy_connect - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy_connect - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_connect - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_proxy_connect - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so /opt:ref
+
+!ELSEIF "$(CFG)" == "mod_proxy_connect - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy_connect - Win32 Release"
+# Name "mod_proxy_connect - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_connect.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_proxy_connect - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_connect.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_connect.so "proxy_connect_module for Apache" ../../include/ap_release.h > .\mod_proxy_connect.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_proxy_connect - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_connect.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_connect.so "proxy_connect_module for Apache" ../../include/ap_release.h > .\mod_proxy_connect.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_ftp.dsp b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_ftp.dsp
new file mode 100644
index 00000000..3dfe0b7e
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_ftp.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_ftp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_ftp - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_ftp.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_ftp.mak" CFG="mod_proxy_ftp - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy_ftp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_ftp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_proxy_ftp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_ftp_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so /opt:ref
+
+!ELSEIF "$(CFG)" == "mod_proxy_ftp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_ftp_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy_ftp - Win32 Release"
+# Name "mod_proxy_ftp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_ftp.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_proxy_ftp - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ftp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_ftp.so "proxy_ftp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ftp.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_proxy_ftp - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ftp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_ftp.so "proxy_ftp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ftp.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_http.dsp b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_http.dsp
new file mode 100644
index 00000000..d8f29006
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/mod_proxy_http.dsp
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_http" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_http - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_http.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "mod_proxy_http.mak" CFG="mod_proxy_http - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "mod_proxy_http - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_http - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "mod_proxy_http - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_http_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so /opt:ref
+
+!ELSEIF "$(CFG)" == "mod_proxy_http - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_http_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+
+!ENDIF
+
+# Begin Target
+
+# Name "mod_proxy_http - Win32 Release"
+# Name "mod_proxy_http - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_http.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF "$(CFG)" == "mod_proxy_http - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_http.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_http.so "proxy_http_module for Apache" ../../include/ap_release.h > .\mod_proxy_http.rc
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "mod_proxy_http - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_http.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ awk -f ../../build/win32/win32ver.awk mod_proxy_http.so "proxy_http_module for Apache" ../../include/ap_release.h > .\mod_proxy_http.rc
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/modules.mk b/rubbos/app/httpd-2.0.64/modules/proxy/modules.mk
new file mode 100644
index 00000000..ceb52a1b
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/modules.mk
@@ -0,0 +1,3 @@
+DISTCLEAN_TARGETS = modules.mk
+static =
+shared =
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/proxy_connect.c b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_connect.c
new file mode 100644
index 00000000..20e40ebb
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_connect.c
@@ -0,0 +1,377 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* CONNECT method for Apache proxy */
+
+#define CORE_PRIVATE
+
+#include "mod_proxy.h"
+#include "apr_poll.h"
+
+module AP_MODULE_DECLARE_DATA proxy_connect_module;
+
+int ap_proxy_connect_canon(request_rec *r, char *url);
+int ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyname,
+ apr_port_t proxyport);
+
+/*
+ * This handles Netscape CONNECT method secure proxy requests.
+ * A connection is opened to the specified host and data is
+ * passed through between the WWW site and the browser.
+ *
+ * This code is based on the INTERNET-DRAFT document
+ * "Tunneling SSL Through a WWW Proxy" currently at
+ * http://www.mcom.com/newsref/std/tunneling_ssl.html.
+ *
+ * If proxyhost and proxyport are set, we send a CONNECT to
+ * the specified proxy..
+ *
+ * FIXME: this doesn't log the number of bytes sent, but
+ * that may be okay, since the data is supposed to
+ * be transparent. In fact, this doesn't log at all
+ * yet. 8^)
+ * FIXME: doesn't check any headers initally sent from the
+ * client.
+ * FIXME: should allow authentication, but hopefully the
+ * generic proxy authentication is good enough.
+ * FIXME: no check for r->assbackwards, whatever that is.
+ */
+
+static int
+allowed_port(proxy_server_conf *conf, int port)
+{
+ int i;
+ int *list = (int *) conf->allowed_connect_ports->elts;
+
+ for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
+ if(port == list[i])
+ return 1;
+ }
+ return 0;
+}
+
+/* canonicalise CONNECT URLs. */
+int ap_proxy_connect_canon(request_rec *r, char *url)
+{
+
+ if (r->method_number != M_CONNECT) {
+ return DECLINED;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: canonicalising URL %s", url);
+
+ return OK;
+}
+
+/* CONNECT handler */
+int ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyname,
+ apr_port_t proxyport)
+{
+ apr_pool_t *p = r->pool;
+ apr_socket_t *sock;
+ apr_status_t err, rv;
+ apr_size_t i, o, nbytes;
+ char buffer[HUGE_STRING_LEN];
+ apr_socket_t *client_socket = ap_get_module_config(r->connection->conn_config, &core_module);
+ int failed;
+ apr_pollfd_t *pollfd;
+ apr_int32_t pollcnt;
+ apr_int16_t pollevent;
+ apr_sockaddr_t *uri_addr, *connect_addr;
+
+ apr_uri_t uri;
+ const char *connectname;
+ int connectport = 0;
+
+ /* is this for us? */
+ if (r->method_number != M_CONNECT) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: declining URL %s", url);
+ return DECLINED;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: serving URL %s", url);
+
+
+ /*
+ * Step One: Determine Who To Connect To
+ *
+ * Break up the URL to determine the host to connect to
+ */
+
+ /* we break the URL into host, port, uri */
+ if (APR_SUCCESS != apr_uri_parse_hostinfo(p, url, &uri)) {
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port);
+
+ /* do a DNS lookup for the destination host */
+ err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 0, p);
+
+ /* are we connecting directly, or via a proxy? */
+ if (proxyname) {
+ connectname = proxyname;
+ connectport = proxyport;
+ err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p);
+ }
+ else {
+ connectname = uri.hostname;
+ connectport = uri.port;
+ connect_addr = uri_addr;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport);
+
+ /* check if ProxyBlock directive on this host */
+ if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
+ }
+
+ /* Check if it is an allowed port */
+ if (conf->allowed_connect_ports->nelts == 0) {
+ /* Default setting if not overridden by AllowCONNECT */
+ switch (uri.port) {
+ case APR_URI_HTTPS_DEFAULT_PORT:
+ case APR_URI_SNEWS_DEFAULT_PORT:
+ break;
+ default:
+ /* XXX can we call ap_proxyerror() here to get a nice log message? */
+ return HTTP_FORBIDDEN;
+ }
+ } else if(!allowed_port(conf, uri.port)) {
+ /* XXX can we call ap_proxyerror() here to get a nice log message? */
+ return HTTP_FORBIDDEN;
+ }
+
+ /*
+ * Step Two: Make the Connection
+ *
+ * We have determined who to connect to. Now make the connection.
+ */
+
+ /* get all the possible IP addresses for the destname and loop through them
+ * until we get a successful connection
+ */
+ if (APR_SUCCESS != err) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+ "DNS lookup failure for: ",
+ connectname, NULL));
+ }
+
+ /*
+ * At this point we have a list of one or more IP addresses of
+ * the machine to connect to. If configured, reorder this
+ * list so that the "best candidate" is first try. "best
+ * candidate" could mean the least loaded server, the fastest
+ * responding server, whatever.
+ *
+ * For now we do nothing, ie we get DNS round robin.
+ * XXX FIXME
+ */
+ failed = ap_proxy_connect_to_backend(&sock, "CONNECT", connect_addr,
+ connectname, conf, r->server,
+ r->pool);
+
+ /* handle a permanent error from the above loop */
+ if (failed) {
+ if (proxyname) {
+ return DECLINED;
+ }
+ else {
+ return HTTP_BAD_GATEWAY;
+ }
+ }
+
+ /*
+ * Step Three: Send the Request
+ *
+ * Send the HTTP/1.1 CONNECT request to the remote server
+ */
+
+ /* we are acting as a tunnel - the output filter stack should
+ * be completely empty, because when we are done here we are done completely.
+ * We add the NULL filter to the stack to do this...
+ */
+ r->output_filters = NULL;
+ r->connection->output_filters = NULL;
+
+
+ /* If we are connecting through a remote proxy, we need to pass
+ * the CONNECT request on to it.
+ */
+ if (proxyport) {
+ /* FIXME: Error checking ignored.
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: sending the CONNECT request to the remote proxy");
+ nbytes = apr_snprintf(buffer, sizeof(buffer),
+ "CONNECT %s HTTP/1.0" CRLF, r->uri);
+ apr_send(sock, buffer, &nbytes);
+ nbytes = apr_snprintf(buffer, sizeof(buffer),
+ "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+ apr_send(sock, buffer, &nbytes);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: Returning 200 OK Status");
+ nbytes = apr_snprintf(buffer, sizeof(buffer),
+ "HTTP/1.0 200 Connection Established" CRLF);
+ ap_xlate_proto_to_ascii(buffer, nbytes);
+ apr_send(client_socket, buffer, &nbytes);
+ nbytes = apr_snprintf(buffer, sizeof(buffer),
+ "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+ ap_xlate_proto_to_ascii(buffer, nbytes);
+ apr_send(client_socket, buffer, &nbytes);
+#if 0
+ /* This is safer code, but it doesn't work yet. I'm leaving it
+ * here so that I can fix it later.
+ */
+ r->status = HTTP_OK;
+ r->header_only = 1;
+ apr_table_set(r->headers_out, "Proxy-agent: %s", ap_get_server_version());
+ ap_rflush(r);
+#endif
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: setting up poll()");
+
+ /*
+ * Step Four: Handle Data Transfer
+ *
+ * Handle two way transfer of data over the socket (this is a tunnel).
+ */
+
+/* r->sent_bodyct = 1;*/
+
+ if((rv = apr_poll_setup(&pollfd, 2, r->pool)) != APR_SUCCESS)
+ {
+ apr_socket_close(sock);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: CONNECT: error apr_poll_setup()");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* Add client side to the poll */
+ apr_poll_socket_add(pollfd, client_socket, APR_POLLIN);
+
+ /* Add the server side to the poll */
+ apr_poll_socket_add(pollfd, sock, APR_POLLIN);
+
+ while (1) { /* Infinite loop until error (one side closes the connection) */
+/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: CONNECT: going to sleep (poll)");*/
+ if ((rv = apr_poll(pollfd, 2, &pollcnt, -1)) != APR_SUCCESS)
+ {
+ apr_socket_close(sock);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: CONNECT: error apr_poll()");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: woke from select(), i=%d", pollcnt);*/
+
+ if (pollcnt) {
+ apr_poll_revents_get(&pollevent, sock, pollfd);
+ if (pollevent & APR_POLLIN) {
+/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: sock was set");*/
+ nbytes = sizeof(buffer);
+ if (apr_recv(sock, buffer, &nbytes) == APR_SUCCESS) {
+ o = 0;
+ i = nbytes;
+ while(i > 0)
+ {
+ nbytes = i;
+ /* This is just plain wrong. No module should ever write directly
+ * to the client. For now, this works, but this is high on my list of
+ * things to fix. The correct line is:
+ * if ((nbytes = ap_rwrite(buffer + o, nbytes, r)) < 0)
+ * rbb
+ */
+ if (apr_send(client_socket, buffer + o, &nbytes) != APR_SUCCESS)
+ break;
+ o += nbytes;
+ i -= nbytes;
+ }
+ }
+ else
+ break;
+ }
+ else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP))
+ break;
+
+
+ apr_poll_revents_get(&pollevent, client_socket, pollfd);
+ if (pollevent & APR_POLLIN) {
+/* ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: client was set");*/
+ nbytes = sizeof(buffer);
+ if (apr_recv(client_socket, buffer, &nbytes) == APR_SUCCESS) {
+ o = 0;
+ i = nbytes;
+ while(i > 0)
+ {
+ nbytes = i;
+ if (apr_send(sock, buffer + o, &nbytes) != APR_SUCCESS)
+ break;
+ o += nbytes;
+ i -= nbytes;
+ }
+ }
+ else
+ break;
+ }
+ else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP))
+ break;
+ }
+ else
+ break;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: CONNECT: finished with poll() - cleaning up");
+
+ /*
+ * Step Five: Clean Up
+ *
+ * Close the socket and clean up
+ */
+
+ apr_socket_close(sock);
+
+ return OK;
+}
+
+static void ap_proxy_connect_register_hook(apr_pool_t *p)
+{
+ proxy_hook_scheme_handler(ap_proxy_connect_handler, NULL, NULL, APR_HOOK_MIDDLE);
+ proxy_hook_canon_handler(ap_proxy_connect_canon, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_connect_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command apr_table_t */
+ ap_proxy_connect_register_hook /* register hooks */
+};
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/proxy_ftp.c b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_ftp.c
new file mode 100644
index 00000000..cbbf23c9
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_ftp.c
@@ -0,0 +1,1936 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* FTP routines for Apache proxy */
+
+#include "mod_proxy.h"
+#if APR_HAVE_TIME_H
+#include <time.h>
+#endif
+
+#define AUTODETECT_PWD
+/* Automatic timestamping (Last-Modified header) based on MDTM is used if:
+ * 1) the FTP server supports the MDTM command and
+ * 2) HAVE_TIMEGM (preferred) or HAVE_GMTOFF is available at compile time
+ */
+#define USE_MDTM
+
+
+module AP_MODULE_DECLARE_DATA proxy_ftp_module;
+
+int ap_proxy_ftp_canon(request_rec *r, char *url);
+int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyhost,
+ apr_port_t proxyport);
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t * f,
+ apr_bucket_brigade *bb);
+
+
+/*
+ * Decodes a '%' escaped string, and returns the number of characters
+ */
+static int decodeenc(char *x)
+{
+ int i, j, ch;
+
+ if (x[0] == '\0')
+ return 0; /* special case for no characters */
+ for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
+ /* decode it if not already done */
+ ch = x[i];
+ if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ }
+ x[j] = ch;
+ }
+ x[j] = '\0';
+ return j;
+}
+
+/*
+ * Escape the globbing characters in a path used as argument to
+ * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
+ * ftpd assumes '\\' as a quoting character to escape special characters.
+ * Returns: escaped string
+ */
+#define FTP_GLOBBING_CHARS "*?[{~"
+static char *ftp_escape_globbingchars(apr_pool_t *p, const char *path)
+{
+ char *ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
+ char *d;
+ for (d = ret; *path; ++path) {
+ if (strchr(FTP_GLOBBING_CHARS, *path) != NULL)
+ *d++ = '\\';
+ *d++ = *path;
+ }
+ *d = '\0';
+ return ret;
+}
+
+/*
+ * Check for globbing characters in a path used as argument to
+ * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
+ * ftpd assumes '\\' as a quoting character to escape special characters.
+ * Returns: 0 (no globbing chars, or all globbing chars escaped), 1 (globbing chars)
+ */
+static int ftp_check_globbingchars(const char *path)
+{
+ for ( ; *path; ++path) {
+ if (*path == '\\')
+ ++path;
+ if (*path != '\0' && strchr(FTP_GLOBBING_CHARS, *path) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * checks an encoded ftp string for bad characters, namely, CR, LF or
+ * non-ascii character
+ */
+static int ftp_check_string(const char *x)
+{
+ int i, ch = 0;
+#if APR_CHARSET_EBCDIC
+ char buf[1];
+#endif
+
+ for (i = 0; x[i] != '\0'; i++) {
+ ch = x[i];
+ if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ }
+#if !APR_CHARSET_EBCDIC
+ if (ch == '\015' || ch == '\012' || (ch & 0x80))
+#else /* APR_CHARSET_EBCDIC */
+ if (ch == '\r' || ch == '\n')
+ return 0;
+ buf[0] = ch;
+ ap_xlate_proto_to_ascii(buf, 1);
+ if (buf[0] & 0x80)
+#endif /* APR_CHARSET_EBCDIC */
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Canonicalise ftp URLs.
+ */
+int ap_proxy_ftp_canon(request_rec *r, char *url)
+{
+ char *user, *password, *host, *path, *parms, *strp, sport[7];
+ apr_pool_t *p = r->pool;
+ const char *err;
+ apr_port_t port, def_port;
+
+ /* */
+ if (strncasecmp(url, "ftp:", 4) == 0) {
+ url += 4;
+ }
+ else {
+ return DECLINED;
+ }
+ def_port = apr_uri_port_of_scheme("ftp");
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: canonicalising URL %s", url);
+
+ port = def_port;
+ err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port);
+ if (err)
+ return HTTP_BAD_REQUEST;
+ if (user != NULL && !ftp_check_string(user))
+ return HTTP_BAD_REQUEST;
+ if (password != NULL && !ftp_check_string(password))
+ return HTTP_BAD_REQUEST;
+
+ /* now parse path/parameters args, according to rfc1738 */
+ /*
+ * N.B. if this isn't a true proxy request, then the URL path (but not
+ * query args) has already been decoded. This gives rise to the problem
+ * of a ; being decoded into the path.
+ */
+ strp = strchr(url, ';');
+ if (strp != NULL) {
+ *(strp++) = '\0';
+ parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm,
+ r->proxyreq);
+ if (parms == NULL)
+ return HTTP_BAD_REQUEST;
+ }
+ else
+ parms = "";
+
+ path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
+ if (path == NULL)
+ return HTTP_BAD_REQUEST;
+ if (!ftp_check_string(path))
+ return HTTP_BAD_REQUEST;
+
+ if (r->proxyreq && r->args != NULL) {
+ if (strp != NULL) {
+ strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
+ if (strp == NULL)
+ return HTTP_BAD_REQUEST;
+ parms = apr_pstrcat(p, parms, "?", strp, NULL);
+ }
+ else {
+ strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
+ if (strp == NULL)
+ return HTTP_BAD_REQUEST;
+ path = apr_pstrcat(p, path, "?", strp, NULL);
+ }
+ r->args = NULL;
+ }
+
+/* now, rebuild URL */
+
+ if (port != def_port)
+ apr_snprintf(sport, sizeof(sport), ":%d", port);
+ else
+ sport[0] = '\0';
+
+ if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
+ host = apr_pstrcat(p, "[", host, "]", NULL);
+ }
+ r->filename = apr_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "",
+ (password != NULL) ? ":" : "",
+ (password != NULL) ? password : "",
+ (user != NULL) ? "@" : "", host, sport, "/", path,
+ (parms[0] != '\0') ? ";" : "", parms, NULL);
+
+ return OK;
+}
+
+/* we chop lines longer than 80 characters */
+#define MAX_LINE_LEN 80
+
+/*
+ * Reads response lines, returns both the ftp status code and
+ * remembers the response message in the supplied buffer
+ */
+static int ftp_getrc_msg(conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char *msgbuf, int msglen)
+{
+ int status;
+ char response[MAX_LINE_LEN];
+ char buff[5];
+ char *mb = msgbuf, *me = &msgbuf[msglen];
+ apr_status_t rv;
+ int eos;
+
+ if (APR_SUCCESS != (rv = ap_proxy_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
+ return -1;
+ }
+/*
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+ "proxy: <FTP: %s", response);
+*/
+ if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) ||
+ !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
+ status = 0;
+ else
+ status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0';
+
+ mb = apr_cpystrn(mb, response + 4, me - mb);
+
+ if (response[3] == '-') {
+ memcpy(buff, response, 3);
+ buff[3] = ' ';
+ do {
+ if (APR_SUCCESS != (rv = ap_proxy_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
+ return -1;
+ }
+ mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb);
+ } while (memcmp(response, buff, 4) != 0);
+ }
+
+ return status;
+}
+
+/* this is a filter that turns a raw ASCII directory listing into pretty HTML */
+
+/* ideally, mod_proxy should simply send the raw directory list up the filter
+ * stack to mod_autoindex, which in theory should turn the raw ascii into
+ * pretty html along with all the bells and whistles it provides...
+ *
+ * all in good time...! :)
+ */
+
+typedef struct {
+ apr_bucket_brigade *in;
+ char buffer[MAX_STRING_LEN];
+ enum {
+ HEADER, BODY, FOOTER
+ } state;
+} proxy_dir_ctx_t;
+
+/* fallback regex for ls -s1; ($0..$2) == 3 */
+#define LS_REG_PATTERN "^ *([0-9]+) +([^ ]+)$"
+#define LS_REG_MATCH 3
+
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
+{
+ request_rec *r = f->r;
+ conn_rec *c = r->connection;
+ apr_pool_t *p = r->pool;
+ apr_bucket_brigade *out = apr_brigade_create(p, c->bucket_alloc);
+ apr_status_t rv;
+
+ register int n;
+ char *dir, *path, *reldir, *site, *str, *type;
+
+ const char *pwd = apr_table_get(r->notes, "Directory-PWD");
+ const char *readme = apr_table_get(r->notes, "Directory-README");
+
+ proxy_dir_ctx_t *ctx = f->ctx;
+
+ if (!ctx) {
+ f->ctx = ctx = apr_pcalloc(p, sizeof(*ctx));
+ ctx->in = apr_brigade_create(p, c->bucket_alloc);
+ ctx->buffer[0] = 0;
+ ctx->state = HEADER;
+ }
+
+ /* combine the stored and the new */
+ APR_BRIGADE_CONCAT(ctx->in, in);
+
+ if (HEADER == ctx->state) {
+
+ /* basedir is either "", or "/%2f" for the "squid %2f hack" */
+ const char *basedir = ""; /* By default, path is relative to the $HOME dir */
+ char *wildcard = NULL;
+
+ /* Save "scheme://site" prefix without password */
+ site = apr_uri_unparse(p, &f->r->parsed_uri, APR_URI_UNP_OMITPASSWORD | APR_URI_UNP_OMITPATHINFO);
+ /* ... and path without query args */
+ path = apr_uri_unparse(p, &f->r->parsed_uri, APR_URI_UNP_OMITSITEPART | APR_URI_UNP_OMITQUERY);
+
+ /* If path began with /%2f, change the basedir */
+ if (strncasecmp(path, "/%2f", 4) == 0) {
+ basedir = "/%2f";
+ }
+
+ /* Strip off a type qualifier. It is ignored for dir listings */
+ if ((type = strstr(path, ";type=")) != NULL)
+ *type++ = '\0';
+
+ (void)decodeenc(path);
+
+ while (path[1] == '/') /* collapse multiple leading slashes to one */
+ ++path;
+
+ reldir = strrchr(path, '/');
+ if (reldir != NULL && ftp_check_globbingchars(reldir)) {
+ wildcard = &reldir[1];
+ reldir[0] = '\0'; /* strip off the wildcard suffix */
+ }
+
+ /* Copy path, strip (all except the last) trailing slashes */
+ /* (the trailing slash is needed for the dir component loop below) */
+ path = dir = apr_pstrcat(p, path, "/", NULL);
+ for (n = strlen(path); n > 1 && path[n - 1] == '/' && path[n - 2] == '/'; --n)
+ path[n - 1] = '\0';
+
+ /* Add a link to the root directory (if %2f hack was used) */
+ str = (basedir[0] != '\0') ? "<a href=\"/%2f/\">%2f</a>/" : "";
+
+ /* print "ftp://host/" */
+ str = apr_psprintf(p, DOCTYPE_HTML_3_2
+ "<html>\n <head>\n <title>%s%s%s</title>\n"
+ " </head>\n"
+ " <body>\n <h2>Directory of "
+ "<a href=\"/\">%s</a>/%s",
+ site, basedir, ap_escape_html(p, path),
+ site, str);
+
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str),
+ p, c->bucket_alloc));
+
+ for (dir = path+1; (dir = strchr(dir, '/')) != NULL; )
+ {
+ *dir = '\0';
+ if ((reldir = strrchr(path+1, '/'))==NULL) {
+ reldir = path+1;
+ }
+ else
+ ++reldir;
+ /* print "path/" component */
+ str = apr_psprintf(p, "<a href=\"%s%s/\">%s</a>/", basedir,
+ ap_escape_uri(p, path),
+ ap_escape_html(p, reldir));
+ *dir = '/';
+ while (*dir == '/')
+ ++dir;
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str,
+ strlen(str), p,
+ c->bucket_alloc));
+ }
+ if (wildcard != NULL) {
+ wildcard = ap_escape_html(p, wildcard);
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(wildcard,
+ strlen(wildcard), p,
+ c->bucket_alloc));
+ }
+
+ /* If the caller has determined the current directory, and it differs */
+ /* from what the client requested, then show the real name */
+ if (pwd == NULL || strncmp(pwd, path, strlen(pwd)) == 0) {
+ str = apr_psprintf(p, "</h2>\n\n <hr />\n\n<pre>");
+ }
+ else {
+ str = apr_psprintf(p, "</h2>\n\n(%s)\n\n <hr />\n\n<pre>",
+ ap_escape_html(p, pwd));
+ }
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str),
+ p, c->bucket_alloc));
+
+ /* print README */
+ if (readme) {
+ str = apr_psprintf(p, "%s\n</pre>\n\n<hr />\n\n<pre>\n",
+ ap_escape_html(p, readme));
+
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str,
+ strlen(str), p,
+ c->bucket_alloc));
+ }
+
+ /* make sure page intro gets sent out */
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+ if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+ return rv;
+ }
+ apr_brigade_cleanup(out);
+
+ ctx->state = BODY;
+ }
+
+ /* loop through each line of directory */
+ while (BODY == ctx->state) {
+ char *filename;
+ int found = 0;
+ int eos = 0;
+
+ regex_t *re = NULL;
+ regmatch_t re_result[LS_REG_MATCH];
+
+ /* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */
+ re = ap_pregcomp(p, LS_REG_PATTERN, REG_EXTENDED);
+ ap_assert(re != NULL);
+
+ /* get a complete line */
+ /* if the buffer overruns - throw data away */
+ while (!found && !APR_BRIGADE_EMPTY(ctx->in)) {
+ char *pos, *response;
+ apr_size_t len, max;
+ apr_bucket *e;
+
+ e = APR_BRIGADE_FIRST(ctx->in);
+ if (APR_BUCKET_IS_EOS(e)) {
+ eos = 1;
+ break;
+ }
+ if (APR_SUCCESS != (rv = apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ))) {
+ return rv;
+ }
+ pos = memchr(response, APR_ASCII_LF, len);
+ if (pos != NULL) {
+ if ((response + len) != (pos + 1)) {
+ len = pos - response + 1;
+ apr_bucket_split(e, pos - response + 1);
+ }
+ found = 1;
+ }
+ max = sizeof(ctx->buffer) - strlen(ctx->buffer) - 1;
+ if (len > max) {
+ len = max;
+ }
+
+ /* len+1 to leave space for the trailing nil char */
+ apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len+1);
+
+ APR_BUCKET_REMOVE(e);
+ apr_bucket_destroy(e);
+ }
+
+ /* EOS? jump to footer */
+ if (eos) {
+ ctx->state = FOOTER;
+ break;
+ }
+
+ /* not complete? leave and try get some more */
+ if (!found) {
+ return APR_SUCCESS;
+ }
+
+ {
+ apr_size_t n = strlen(ctx->buffer);
+ if (ctx->buffer[n-1] == CRLF[1]) /* strip trailing '\n' */
+ ctx->buffer[--n] = '\0';
+ if (ctx->buffer[n-1] == CRLF[0]) /* strip trailing '\r' if present */
+ ctx->buffer[--n] = '\0';
+ }
+
+ /* a symlink? */
+ if (ctx->buffer[0] == 'l' && (filename = strstr(ctx->buffer, " -> ")) != NULL) {
+ char *link_ptr = filename;
+
+ do {
+ filename--;
+ } while (filename[0] != ' ' && filename > ctx->buffer);
+ if (filename > ctx->buffer)
+ *(filename++) = '\0';
+ *(link_ptr++) = '\0';
+ str = apr_psprintf(p, "%s <a href=\"%s\">%s %s</a>\n",
+ ap_escape_html(p, ctx->buffer),
+ ap_escape_uri(p, filename),
+ ap_escape_html(p, filename),
+ ap_escape_html(p, link_ptr));
+ }
+
+ /* a directory/file? */
+ else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) {
+ int searchidx = 0;
+ char *searchptr = NULL;
+ int firstfile = 1;
+ if (apr_isdigit(ctx->buffer[0])) { /* handle DOS dir */
+ searchptr = strchr(ctx->buffer, '<');
+ if (searchptr != NULL)
+ *searchptr = '[';
+ searchptr = strchr(ctx->buffer, '>');
+ if (searchptr != NULL)
+ *searchptr = ']';
+ }
+
+ filename = strrchr(ctx->buffer, ' ');
+ *(filename++) = '\0';
+
+ /* handle filenames with spaces in 'em */
+ if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
+ firstfile = 0;
+ searchidx = filename - ctx->buffer;
+ }
+ else if (searchidx != 0 && ctx->buffer[searchidx] != 0) {
+ *(--filename) = ' ';
+ ctx->buffer[searchidx - 1] = '\0';
+ filename = &ctx->buffer[searchidx];
+ }
+
+ /* Append a slash to the HREF link for directories */
+ if (!strcmp(filename, ".") || !strcmp(filename, "..") || ctx->buffer[0] == 'd') {
+ str = apr_psprintf(p, "%s <a href=\"%s/\">%s</a>\n",
+ ap_escape_html(p, ctx->buffer),
+ ap_escape_uri(p, filename),
+ ap_escape_html(p, filename));
+ }
+ else {
+ str = apr_psprintf(p, "%s <a href=\"%s\">%s</a>\n",
+ ap_escape_html(p, ctx->buffer),
+ ap_escape_uri(p, filename),
+ ap_escape_html(p, filename));
+ }
+ }
+ /* Try a fallback for listings in the format of "ls -s1" */
+ else if (0 == ap_regexec(re, ctx->buffer, LS_REG_MATCH, re_result, 0)) {
+
+ filename = apr_pstrndup(p, &ctx->buffer[re_result[2].rm_so], re_result[2].rm_eo - re_result[2].rm_so);
+
+ str = apr_pstrcat(p, ap_escape_html(p, apr_pstrndup(p, ctx->buffer, re_result[2].rm_so)),
+ "<a href=\"", ap_escape_uri(p, filename), "\">",
+ ap_escape_html(p, filename), "</a>\n", NULL);
+ }
+ else {
+ strcat(ctx->buffer, "\n"); /* re-append the newline */
+ str = ap_escape_html(p, ctx->buffer);
+ }
+
+ /* erase buffer for next time around */
+ ctx->buffer[0] = 0;
+
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p,
+ c->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+ if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+ return rv;
+ }
+ apr_brigade_cleanup(out);
+
+ }
+
+ if (FOOTER == ctx->state) {
+ str = apr_psprintf(p, "</pre>\n\n <hr />\n\n %s\n\n </body>\n</html>\n", ap_psignature("", r));
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p,
+ c->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(out, apr_bucket_eos_create(c->bucket_alloc));
+ if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+ return rv;
+ }
+ apr_brigade_destroy(out);
+ }
+
+ return APR_SUCCESS;
+}
+
+/* Parse EPSV reply and return port, or zero on error. */
+static apr_port_t parse_epsv_reply(const char *reply)
+{
+ const char *p;
+ char *ep;
+ long port;
+
+ /* Reply syntax per RFC 2428: "229 blah blah (|||port|)" where '|'
+ * can be any character in ASCII from 33-126, obscurely. Verify
+ * the syntax. */
+ p = ap_strchr_c(reply, '(');
+ if (p == NULL || !p[1] || p[1] != p[2] || p[1] != p[3]
+ || p[4] == p[1]) {
+ return 0;
+ }
+
+ errno = 0;
+ port = strtol(p + 4, &ep, 10);
+ if (errno || port < 1 || port > 65535 || ep[0] != p[1] || ep[1] != ')') {
+ return 0;
+ }
+
+ return (apr_port_t)port;
+}
+
+/*
+ * Generic "send FTP command to server" routine, using the control socket.
+ * Returns the FTP returncode (3 digit code)
+ * Allows for tracing the FTP protocol (in LogLevel debug)
+ */
+static int
+proxy_ftp_command(const char *cmd, request_rec *r, conn_rec *ftp_ctrl,
+ apr_bucket_brigade *bb, char **pmessage)
+{
+ char *crlf;
+ int rc;
+ char message[HUGE_STRING_LEN];
+
+ /* If cmd == NULL, we retrieve the next ftp response line */
+ if (cmd != NULL) {
+ conn_rec *c = r->connection;
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(cmd, strlen(cmd), r->pool, c->bucket_alloc));
+ APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(c->bucket_alloc));
+ ap_pass_brigade(ftp_ctrl->output_filters, bb);
+
+ /* strip off the CRLF for logging */
+ apr_cpystrn(message, cmd, sizeof(message));
+ if ((crlf = strchr(message, '\r')) != NULL ||
+ (crlf = strchr(message, '\n')) != NULL)
+ *crlf = '\0';
+ if (strncmp(message,"PASS ", 5) == 0)
+ strcpy(&message[5], "****");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy:>FTP: %s", message);
+ }
+
+ rc = ftp_getrc_msg(ftp_ctrl, bb, message, sizeof message);
+ if (rc == -1 || rc == 421)
+ strcpy(message,"<unable to read result>");
+ if ((crlf = strchr(message, '\r')) != NULL ||
+ (crlf = strchr(message, '\n')) != NULL)
+ *crlf = '\0';
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy:<FTP: %3.3u %s", rc, message);
+
+ if (pmessage != NULL)
+ *pmessage = apr_pstrdup(r->pool, message);
+
+ return rc;
+}
+
+/* Set ftp server to TYPE {A,I,E} before transfer of a directory or file */
+static int ftp_set_TYPE(char xfer_type, request_rec *r, conn_rec *ftp_ctrl,
+ apr_bucket_brigade *bb, char **pmessage)
+{
+ char old_type[2] = { 'A', '\0' }; /* After logon, mode is ASCII */
+ int ret = HTTP_OK;
+ int rc;
+
+ /* set desired type */
+ old_type[0] = xfer_type;
+
+ rc = proxy_ftp_command(apr_pstrcat(r->pool, "TYPE ", old_type, CRLF, NULL),
+ r, ftp_ctrl, bb, pmessage);
+/* responses: 200, 421, 500, 501, 504, 530 */
+ /* 200 Command okay. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 504 Command not implemented for that parameter. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ ret = ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ else if (rc != 200 && rc != 504) {
+ ret = ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Unable to set transfer type");
+ }
+/* Allow not implemented */
+ else if (rc == 504)
+ /* ignore it silently */;
+
+ return ret;
+}
+
+
+/* Return the current directory which we have selected on the FTP server, or NULL */
+static char *ftp_get_PWD(request_rec *r, conn_rec *ftp_ctrl, apr_bucket_brigade *bb)
+{
+ char *cwd = NULL;
+ char *ftpmessage = NULL;
+
+ /* responses: 257, 500, 501, 502, 421, 550 */
+ /* 257 "<directory-name>" <commentary> */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 550 Requested action not taken. */
+ switch (proxy_ftp_command("PWD" CRLF, r, ftp_ctrl, bb, &ftpmessage)) {
+ case -1:
+ case 421:
+ case 550:
+ ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Failed to read PWD on ftp server");
+ break;
+
+ case 257: {
+ const char *dirp = ftpmessage;
+ cwd = ap_getword_conf(r->pool, &dirp);
+ }
+ }
+ return cwd;
+}
+
+
+/* Common routine for failed authorization (i.e., missing or wrong password)
+ * to an ftp service. This causes most browsers to retry the request
+ * with username and password (which was presumably queried from the user)
+ * supplied in the Authorization: header.
+ * Note that we "invent" a realm name which consists of the
+ * ftp://user@host part of the reqest (sans password -if supplied but invalid-)
+ */
+static int ftp_unauthorized(request_rec *r, int log_it)
+{
+ r->proxyreq = PROXYREQ_NONE;
+ /*
+ * Log failed requests if they supplied a password (log username/password
+ * guessing attempts)
+ */
+ if (log_it)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "proxy: missing or failed auth to %s",
+ apr_uri_unparse(r->pool,
+ &r->parsed_uri, APR_URI_UNP_OMITPATHINFO));
+
+ apr_table_setn(r->err_headers_out, "WWW-Authenticate",
+ apr_pstrcat(r->pool, "Basic realm=\"",
+ apr_uri_unparse(r->pool, &r->parsed_uri,
+ APR_URI_UNP_OMITPASSWORD | APR_URI_UNP_OMITPATHINFO),
+ "\"", NULL));
+
+ return HTTP_UNAUTHORIZED;
+}
+
+
+/*
+ * Handles direct access of ftp:// URLs
+ * Original (Non-PASV) version from
+ * Troy Morrison <spiffnet@zoom.com>
+ * PASV added by Chuck
+ * Filters by [Graham Leggett <minfrin@sharp.fm>]
+ */
+int ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyhost,
+ apr_port_t proxyport)
+{
+ apr_pool_t *p = r->pool;
+ conn_rec *c = r->connection;
+ proxy_conn_rec *backend;
+ apr_socket_t *sock, *local_sock, *data_sock = NULL;
+ apr_sockaddr_t *connect_addr;
+ apr_status_t rv;
+ conn_rec *origin, *data = NULL;
+ int err;
+ apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
+ char *buf, *connectname;
+ apr_port_t connectport;
+ char buffer[MAX_STRING_LEN];
+ char *ftpmessage = NULL;
+ char *path, *strp, *type_suffix, *cwd = NULL;
+ apr_uri_t uri;
+ char *user = NULL;
+/* char *account = NULL; how to supply an account in a URL? */
+ const char *password = NULL;
+ int len, rc;
+ int one = 1;
+ char *size = NULL;
+ apr_socket_t *origin_sock = NULL;
+ char xfer_type = 'A'; /* after ftp login, the default is ASCII */
+ int dirlisting = 0;
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+ apr_time_t mtime = 0L;
+#endif
+
+ /* stuff for PASV mode */
+ int connect = 0, use_port = 0;
+ char dates[APR_RFC822_DATE_LEN];
+
+ /* is this for us? */
+ if (proxyhost) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: declining URL %s - proxyhost %s specified:", url, proxyhost);
+ return DECLINED; /* proxy connections are via HTTP */
+ }
+ if (strncasecmp(url, "ftp:", 4)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: declining URL %s - not ftp:", url);
+ return DECLINED; /* only interested in FTP */
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: serving URL %s", url);
+
+ /* create space for state information */
+ backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module);
+ if (!backend) {
+ backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec));
+ backend->connection = NULL;
+ backend->hostname = NULL;
+ backend->port = 0;
+ ap_set_module_config(c->conn_config, &proxy_ftp_module, backend);
+ }
+ if (backend->connection)
+ origin_sock = ap_get_module_config(backend->connection->conn_config, &core_module);
+
+
+ /*
+ * I: Who Do I Connect To? -----------------------
+ *
+ * Break up the URL to determine the host to connect to
+ */
+
+ /* we only support GET and HEAD */
+ if (r->method_number != M_GET)
+ return HTTP_NOT_IMPLEMENTED;
+
+ /* We break the URL into host, port, path-search */
+ if (r->parsed_uri.hostname == NULL) {
+ if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) {
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ apr_psprintf(p, "URI cannot be parsed: %s", url));
+ }
+ connectname = uri.hostname;
+ connectport = uri.port;
+ path = apr_pstrdup(p, uri.path);
+ }
+ else {
+ connectname = r->parsed_uri.hostname;
+ connectport = r->parsed_uri.port;
+ path = apr_pstrdup(p, r->parsed_uri.path);
+ }
+ if (connectport == 0) {
+ connectport = apr_uri_port_of_scheme("ftp");
+ }
+ path = (path != NULL && path[0] != '\0') ? &path[1] : "";
+
+ type_suffix = strchr(path, ';');
+ if (type_suffix != NULL)
+ *(type_suffix++) = '\0';
+
+ if (type_suffix != NULL && strncmp(type_suffix, "type=", 5) == 0
+ && apr_isalpha(type_suffix[5])) {
+ /* "type=d" forces a dir listing.
+ * The other types (i|a|e) are directly used for the ftp TYPE command
+ */
+ if ( ! (dirlisting = (apr_tolower(type_suffix[5]) == 'd')))
+ xfer_type = apr_toupper(type_suffix[5]);
+
+ /* Check valid types, rather than ignoring invalid types silently: */
+ if (strchr("AEI", xfer_type) == NULL)
+ return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
+ "ftp proxy supports only types 'a', 'i', or 'e': \"",
+ type_suffix, "\" is invalid.", NULL));
+ }
+ else {
+ /* make binary transfers the default */
+ xfer_type = 'I';
+ }
+
+
+ /*
+ * The "Authorization:" header must be checked first. We allow the user
+ * to "override" the URL-coded user [ & password ] in the Browsers'
+ * User&Password Dialog. NOTE that this is only marginally more secure
+ * than having the password travel in plain as part of the URL, because
+ * Basic Auth simply uuencodes the plain text password. But chances are
+ * still smaller that the URL is logged regularly.
+ */
+ if ((password = apr_table_get(r->headers_in, "Authorization")) != NULL
+ && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
+ && (password = ap_pbase64decode(r->pool, password))[0] != ':') {
+ /* Check the decoded string for special characters. */
+ if (!ftp_check_string(password)) {
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ "user credentials contained invalid character");
+ }
+ /*
+ * Note that this allocation has to be made from r->connection->pool
+ * because it has the lifetime of the connection. The other
+ * allocations are temporary and can be tossed away any time.
+ */
+ user = ap_getword_nulls(r->connection->pool, &password, ':');
+ r->ap_auth_type = "Basic";
+ r->user = r->parsed_uri.user = user;
+ }
+ else if ((user = r->parsed_uri.user) != NULL) {
+ user = apr_pstrdup(p, user);
+ decodeenc(user);
+ if ((password = r->parsed_uri.password) != NULL) {
+ char *tmp = apr_pstrdup(p, password);
+ decodeenc(tmp);
+ password = tmp;
+ }
+ }
+ else {
+ user = "anonymous";
+ password = "apache-proxy@";
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: connecting %s to %s:%d", url, connectname, connectport);
+
+ /* do a DNS lookup for the destination host */
+ err = apr_sockaddr_info_get(&connect_addr, connectname, APR_UNSPEC, connectport, 0, p);
+
+ /* check if ProxyBlock directive on this host */
+ if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) {
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
+ }
+
+
+ /*
+ * II: Make the Connection -----------------------
+ *
+ * We have determined who to connect to. Now make the connection.
+ */
+
+ /*
+ * get all the possible IP addresses for the destname and loop through
+ * them until we get a successful connection
+ */
+ if (APR_SUCCESS != err) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+ "DNS lookup failure for: ",
+ connectname, NULL));
+ }
+
+ /*
+ * At this point we have a list of one or more IP addresses of the
+ * machine to connect to. If configured, reorder this list so that the
+ * "best candidate" is first try. "best candidate" could mean the least
+ * loaded server, the fastest responding server, whatever.
+ *
+ * For now we do nothing, ie we get DNS round robin. XXX FIXME
+ */
+
+
+ /* try each IP address until we connect successfully */
+ {
+ int failed = 1;
+ while (connect_addr) {
+
+ if ((rv = apr_socket_create(&sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error creating socket");
+ connect_addr = connect_addr->next;
+ continue;
+ }
+
+#if !defined(TPF) && !defined(BEOS)
+ if (conf->recv_buffer_size > 0
+ && (rv = apr_socket_opt_set(sock, APR_SO_RCVBUF,
+ conf->recv_buffer_size))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "apr_socket_opt_set(APR_SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+ }
+#endif
+
+ if (APR_SUCCESS != (rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, one))) {
+ apr_socket_close(sock);
+#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error setting reuseaddr option: apr_socket_opt_set(APR_SO_REUSEADDR)");
+ connect_addr = connect_addr->next;
+ continue;
+#endif /* _OSD_POSIX */
+ }
+
+ /* Set a timeout on the socket */
+ if (conf->timeout_set == 1) {
+ apr_socket_timeout_set(sock, conf->timeout);
+ }
+ else {
+ apr_socket_timeout_set(sock, r->server->timeout);
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: fam %d socket created, trying to connect to %pI (%s)...",
+ connect_addr->family, connect_addr, connectname);
+
+ /* make the connection out of the socket */
+ rv = apr_connect(sock, connect_addr);
+
+ /* if an error occurred, loop round and try again */
+ if (rv != APR_SUCCESS) {
+ apr_socket_close(sock);
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+ "proxy: FTP: attempt to connect to %pI (%s) failed", connect_addr, connectname);
+ connect_addr = connect_addr->next;
+ continue;
+ }
+
+ /* if we get here, all is well */
+ failed = 0;
+ break;
+ }
+
+ /* handle a permanent error from the above loop */
+ if (failed) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,
+ "Could not connect to remote machine: %s port %d",
+ connectname, connectport));
+ }
+ }
+
+ /* the socket is now open, create a new connection */
+ origin = ap_run_create_connection(p, r->server, sock, r->connection->id,
+ r->connection->sbh, c->bucket_alloc);
+ if (!origin) {
+ /*
+ * the peer reset the connection already; ap_run_create_connection() closed
+ * the socket
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: an error occurred creating a new connection to %pI (%s)", connect_addr, connectname);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* if a keepalive connection is floating around, close it first! */
+ /* we might support ftp keepalives later, but not now... */
+ if (backend->connection) {
+ apr_socket_close(origin_sock);
+ backend->connection = NULL;
+ origin_sock = NULL;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: control connection complete");
+
+
+ /*
+ * III: Send Control Request -------------------------
+ *
+ * Log into the ftp server, send the username & password, change to the
+ * correct directory...
+ */
+
+ /* set up the connection filters */
+ rc = ap_run_pre_connection(origin, sock);
+ if (rc != OK && rc != DONE) {
+ origin->aborted = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: pre_connection setup failed (%d)",
+ rc);
+ return rc;
+ }
+
+ /* possible results: */
+ /* 120 Service ready in nnn minutes. */
+ /* 220 Service ready for new user. */
+ /* 421 Service not available, closing control connection. */
+ rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage);
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
+ }
+ if (rc == 120) {
+ /*
+ * RFC2616 states: 14.37 Retry-After
+ *
+ * The Retry-After response-header field can be used with a 503 (Service
+ * Unavailable) response to indicate how long the service is expected
+ * to be unavailable to the requesting client. [...] The value of
+ * this field can be either an HTTP-date or an integer number of
+ * seconds (in decimal) after the time of the response. Retry-After
+ * = "Retry-After" ":" ( HTTP-date | delta-seconds )
+ */
+ char *secs_str = ftpmessage;
+ time_t secs;
+
+ /* Look for a number, preceded by whitespace */
+ while (*secs_str)
+ if ((secs_str==ftpmessage || apr_isspace(secs_str[-1])) &&
+ apr_isdigit(secs_str[0]))
+ break;
+ if (*secs_str != '\0') {
+ secs = atol(secs_str);
+ apr_table_add(r->headers_out, "Retry-After",
+ apr_psprintf(p, "%lu", (unsigned long)(60 * secs)));
+ }
+ return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, ftpmessage);
+ }
+ if (rc != 220) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+
+ rc = proxy_ftp_command(apr_pstrcat(p, "USER ", user, CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ /* possible results; 230, 331, 332, 421, 500, 501, 530 */
+ /* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
+ /* 230 User logged in, proceed. */
+ /* 331 User name okay, need password. */
+ /* 332 Need account for login. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* (This may include errors such as command line too long.) */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
+ }
+ if (rc == 530) {
+ return ftp_unauthorized(r, 1); /* log it: user name guessing
+ * attempt? */
+ }
+ if (rc != 230 && rc != 331) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+
+ if (rc == 331) { /* send password */
+ if (password == NULL) {
+ return ftp_unauthorized(r, 0);
+ }
+
+ rc = proxy_ftp_command(apr_pstrcat(p, "PASS ", password, CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ /* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
+ /* 230 User logged in, proceed. */
+ /* 332 Need account for login. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 503 Bad sequence of commands. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc == 332) {
+ return ap_proxyerror(r, HTTP_UNAUTHORIZED,
+ apr_pstrcat(p, "Need account for login: ", ftpmessage, NULL));
+ }
+ /* @@@ questionable -- we might as well return a 403 Forbidden here */
+ if (rc == 530) {
+ return ftp_unauthorized(r, 1); /* log it: passwd guessing
+ * attempt? */
+ }
+ if (rc != 230 && rc != 202) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+ }
+ apr_table_set(r->notes, "Directory-README", ftpmessage);
+
+
+ /* Special handling for leading "%2f": this enforces a "cwd /"
+ * out of the $HOME directory which was the starting point after login
+ */
+ if (strncasecmp(path, "%2f", 3) == 0) {
+ path += 3;
+ while (*path == '/') /* skip leading '/' (after root %2f) */
+ ++path;
+
+ rc = proxy_ftp_command("CWD /" CRLF, r, origin, bb, &ftpmessage);
+ if (rc == -1 || rc == 421)
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+
+ /*
+ * set the directory (walk directory component by component): this is
+ * what we must do if we don't know the OS type of the remote machine
+ */
+ for (;;) {
+ strp = strchr(path, '/');
+ if (strp == NULL)
+ break;
+ *strp = '\0';
+
+ len = decodeenc(path); /* Note! This decodes a %2f -> "/" */
+
+ if (strchr(path, '/')) { /* are there now any '/' characters? */
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ "Use of /%2f is only allowed at the base directory");
+ }
+
+ /* NOTE: FTP servers do globbing on the path.
+ * So we need to escape the URI metacharacters.
+ * We use a special glob-escaping routine to escape globbing chars.
+ * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
+ */
+ rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
+ ftp_escape_globbingchars(p, path), CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ *strp = '/';
+ /* responses: 250, 421, 500, 501, 502, 530, 550 */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc == 550) {
+ return ap_proxyerror(r, HTTP_NOT_FOUND, ftpmessage);
+ }
+ if (rc != 250) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+
+ path = strp + 1;
+ }
+
+ /*
+ * IV: Make Data Connection? -------------------------
+ *
+ * Try EPSV, if that fails... try PASV, if that fails... try PORT.
+ */
+/* this temporarily switches off EPSV/PASV */
+/*goto bypass;*/
+
+ /* set up data connection - EPSV */
+ {
+ apr_sockaddr_t *data_addr;
+ char *data_ip;
+ apr_port_t data_port;
+
+ /*
+ * The EPSV command replaces PASV where both IPV4 and IPV6 is
+ * supported. Only the port is returned, the IP address is always the
+ * same as that on the control connection. Example: Entering Extended
+ * Passive Mode (|||6446|)
+ */
+ rc = proxy_ftp_command("EPSV" CRLF,
+ r, origin, bb, &ftpmessage);
+ /* possible results: 227, 421, 500, 501, 502, 530 */
+ /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc != 229 && rc != 500 && rc != 501 && rc != 502) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+ else if (rc == 229) {
+ /* Parse the port out of the EPSV reply. */
+ data_port = parse_epsv_reply(ftpmessage);
+
+ if (data_port) {
+ apr_sockaddr_t *epsv_addr;
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: EPSV contacting remote host on port %d",
+ data_port);
+
+ if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error creating EPSV socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+#if !defined (TPF) && !defined(BEOS)
+ if (conf->recv_buffer_size > 0
+ && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,
+ conf->recv_buffer_size))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+ }
+#endif
+
+ /* make the connection */
+ apr_socket_addr_get(&data_addr, APR_REMOTE, sock);
+ apr_sockaddr_ip_get(&data_ip, data_addr);
+ apr_sockaddr_info_get(&epsv_addr, data_ip, connect_addr->family, data_port, 0, p);
+ rv = apr_connect(data_sock, epsv_addr);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+ "proxy: FTP: EPSV attempt to connect to %pI failed - Firewall/NAT?", epsv_addr);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,
+ "EPSV attempt to connect to %pI failed - firewall/NAT?", epsv_addr));
+ }
+ else {
+ connect = 1;
+ }
+ }
+ }
+ }
+
+ /* set up data connection - PASV */
+ if (!connect) {
+ rc = proxy_ftp_command("PASV" CRLF,
+ r, origin, bb, &ftpmessage);
+ /* possible results: 227, 421, 500, 501, 502, 530 */
+ /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc != 227 && rc != 502) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+ else if (rc == 227) {
+ unsigned int h0, h1, h2, h3, p0, p1;
+ char *pstr;
+ char *tok_cntx;
+
+/* FIXME: Check PASV against RFC1123 */
+
+ pstr = ftpmessage;
+ pstr = apr_strtok(pstr, " ", &tok_cntx); /* separate result code */
+ if (pstr != NULL) {
+ if (*(pstr + strlen(pstr) + 1) == '=') {
+ pstr += strlen(pstr) + 2;
+ }
+ else {
+ pstr = apr_strtok(NULL, "(", &tok_cntx); /* separate address &
+ * port params */
+ if (pstr != NULL)
+ pstr = apr_strtok(NULL, ")", &tok_cntx);
+ }
+ }
+
+/* FIXME: Only supports IPV4 - fix in RFC2428 */
+
+ if (pstr != NULL && (sscanf(pstr,
+ "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {
+
+ apr_sockaddr_t *pasv_addr;
+ apr_port_t pasvport = (p1 << 8) + p0;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: PASV contacting host %d.%d.%d.%d:%d",
+ h3, h2, h1, h0, pasvport);
+
+ if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: error creating PASV socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+#if !defined (TPF) && !defined(BEOS)
+ if (conf->recv_buffer_size > 0
+ && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,
+ conf->recv_buffer_size))) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+ }
+#endif
+
+ /* make the connection */
+ apr_sockaddr_info_get(&pasv_addr, apr_psprintf(p, "%d.%d.%d.%d", h3, h2, h1, h0), connect_addr->family, pasvport, 0, p);
+ rv = apr_connect(data_sock, pasv_addr);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+ "proxy: FTP: PASV attempt to connect to %pI failed - Firewall/NAT?", pasv_addr);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,
+ "PASV attempt to connect to %pI failed - firewall/NAT?", pasv_addr));
+ }
+ else {
+ connect = 1;
+ }
+ }
+ }
+ }
+/*bypass:*/
+
+ /* set up data connection - PORT */
+ if (!connect) {
+ apr_sockaddr_t *local_addr;
+ char *local_ip;
+ apr_port_t local_port;
+ unsigned int h0, h1, h2, h3, p0, p1;
+
+ if ((rv = apr_socket_create(&local_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error creating local socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ apr_socket_addr_get(&local_addr, APR_LOCAL, sock);
+ apr_sockaddr_port_get(&local_port, local_addr);
+ apr_sockaddr_ip_get(&local_ip, local_addr);
+
+ if ((rv = apr_socket_opt_set(local_sock, APR_SO_REUSEADDR, one))
+ != APR_SUCCESS) {
+#ifndef _OSD_POSIX /* BS2000 has this option "always on" */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error setting reuseaddr option");
+ return HTTP_INTERNAL_SERVER_ERROR;
+#endif /* _OSD_POSIX */
+ }
+
+ apr_sockaddr_info_get(&local_addr, local_ip, APR_UNSPEC, local_port, 0, r->pool);
+
+ if ((rv = apr_bind(local_sock, local_addr)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error binding to ftp data socket %pI", local_addr);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* only need a short queue */
+ if ((rv = apr_listen(local_sock, 2)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: error listening to ftp data socket %pI", local_addr);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+/* FIXME: Sent PORT here */
+
+ if (local_ip && (sscanf(local_ip,
+ "%d.%d.%d.%d", &h3, &h2, &h1, &h0) == 4)) {
+ p1 = (local_port >> 8);
+ p0 = (local_port & 0xFF);
+
+ rc = proxy_ftp_command(apr_psprintf(p, "PORT %d,%d,%d,%d,%d,%d" CRLF, h3, h2, h1, h0, p1, p0),
+ r, origin, bb, &ftpmessage);
+ /* possible results: 200, 421, 500, 501, 502, 530 */
+ /* 200 Command okay. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc != 200) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, buffer);
+ }
+
+ /* signal that we must use the EPRT/PORT loop */
+ use_port = 1;
+ }
+ else {
+/* IPV6 FIXME:
+ * The EPRT command replaces PORT where both IPV4 and IPV6 is supported. The first
+ * number (1,2) indicates the protocol type. Examples:
+ * EPRT |1|132.235.1.2|6275|
+ * EPRT |2|1080::8:800:200C:417A|5282|
+ */
+ return ap_proxyerror(r, HTTP_NOT_IMPLEMENTED, "Connect to IPV6 ftp server using EPRT not supported. Enable EPSV.");
+ }
+ }
+
+
+ /*
+ * V: Set The Headers -------------------
+ *
+ * Get the size of the request, set up the environment for HTTP.
+ */
+
+ /* set request; "path" holds last path component */
+ len = decodeenc(path);
+
+ if (strchr(path, '/')) { /* are there now any '/' characters? */
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ "Use of /%2f is only allowed at the base directory");
+ }
+
+ /* If len == 0 then it must be a directory (you can't RETR nothing)
+ * Also, don't allow to RETR by wildcard. Instead, create a dirlisting
+ */
+ if (len == 0 || ftp_check_globbingchars(path)) {
+ dirlisting = 1;
+ }
+ else {
+ /* (from FreeBSD ftpd):
+ * SIZE is not in RFC959, but Postel has blessed it and
+ * it will be in the updated RFC.
+ *
+ * Return size of file in a format suitable for
+ * using with RESTART (we just count bytes).
+ */
+ /* from draft-ietf-ftpext-mlst-14.txt:
+ * This value will
+ * change depending on the current STRUcture, MODE and TYPE of the data
+ * connection, or a data connection which would be created were one
+ * created now. Thus, the result of the SIZE command is dependent on
+ * the currently established STRU, MODE and TYPE parameters.
+ */
+ /* Therefore: switch to binary if the user did not specify ";type=a" */
+ ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
+ rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ",
+ ftp_escape_globbingchars(p, path), CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ else if (rc == 213) {/* Size command ok */
+ int j;
+ for (j = 0; apr_isdigit(ftpmessage[j]); j++)
+ ;
+ ftpmessage[j] = '\0';
+ if (ftpmessage[0] != '\0')
+ size = ftpmessage; /* already pstrdup'ed: no copy necessary */
+ }
+ else if (rc == 550) { /* Not a regular file */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: SIZE shows this is a directory");
+ dirlisting = 1;
+ rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
+ ftp_escape_globbingchars(p, path), CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc == 550) {
+ return ap_proxyerror(r, HTTP_NOT_FOUND, ftpmessage);
+ }
+ if (rc != 250) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+ path = "";
+ len = 0;
+ }
+ }
+
+ cwd = ftp_get_PWD(r, origin, bb);
+ if (cwd != NULL) {
+ apr_table_set(r->notes, "Directory-PWD", cwd);
+ }
+
+ if (dirlisting) {
+ ftp_set_TYPE('A', r, origin, bb, NULL);
+ /* If the current directory contains no slash, we are talking to
+ * a non-unix ftp system. Try LIST instead of "LIST -lag", it
+ * should return a long listing anyway (unlike NLST).
+ * Some exotic FTP servers might choke on the "-lag" switch.
+ */
+ /* Note that we do not escape the path here, to allow for
+ * queries like: ftp://user@host/apache/src/server/http_*.c
+ */
+ if (len != 0)
+ buf = apr_pstrcat(p, "LIST ", path, CRLF, NULL);
+ else if (cwd == NULL || strchr(cwd, '/') != NULL)
+ buf = apr_pstrcat(p, "LIST -lag", CRLF, NULL);
+ else
+ buf = "LIST" CRLF;
+ }
+ else {
+ /* switch to binary if the user did not specify ";type=a" */
+ ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+ /* from draft-ietf-ftpext-mlst-14.txt:
+ * The FTP command, MODIFICATION TIME (MDTM), can be used to determine
+ * when a file in the server NVFS was last modified. <..>
+ * The syntax of a time value is:
+ * time-val = 14DIGIT [ "." 1*DIGIT ] <..>
+ * Symbolically, a time-val may be viewed as
+ * YYYYMMDDHHMMSS.sss
+ * The "." and subsequent digits ("sss") are optional. <..>
+ * Time values are always represented in UTC (GMT)
+ */
+ rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path), CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
+ if (rc == 213) {
+ struct {
+ char YYYY[4+1];
+ char MM[2+1];
+ char DD[2+1];
+ char hh[2+1];
+ char mm[2+1];
+ char ss[2+1];
+ } time_val;
+ if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]",
+ time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) {
+ struct tm tms;
+ memset (&tms, '\0', sizeof tms);
+ tms.tm_year = atoi(time_val.YYYY) - 1900;
+ tms.tm_mon = atoi(time_val.MM) - 1;
+ tms.tm_mday = atoi(time_val.DD);
+ tms.tm_hour = atoi(time_val.hh);
+ tms.tm_min = atoi(time_val.mm);
+ tms.tm_sec = atoi(time_val.ss);
+#ifdef HAVE_TIMEGM /* Does system have timegm()? */
+ mtime = timegm(&tms);
+ mtime *= APR_USEC_PER_SEC;
+#elif HAVE_GMTOFF /* does struct tm have a member tm_gmtoff? */
+ /* mktime will subtract the local timezone, which is not what we want.
+ * Add it again because the MDTM string is GMT
+ */
+ mtime = mktime(&tms);
+ mtime += tms.tm_gmtoff;
+ mtime *= APR_USEC_PER_SEC;
+#else
+ mtime = 0L;
+#endif
+ }
+ }
+#endif /* USE_MDTM */
+/* FIXME: Handle range requests - send REST */
+ buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path), CRLF, NULL);
+ }
+ rc = proxy_ftp_command(buf, r, origin, bb, &ftpmessage);
+ /* rc is an intermediate response for the LIST or RETR commands */
+
+ /*
+ * RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530,
+ * 550 NLST: 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 502,
+ * 530
+ */
+ /* 110 Restart marker reply. */
+ /* 125 Data connection already open; transfer starting. */
+ /* 150 File status okay; about to open data connection. */
+ /* 226 Closing data connection. */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 425 Can't open data connection. */
+ /* 426 Connection closed; transfer aborted. */
+ /* 450 Requested file action not taken. */
+ /* 451 Requested action aborted. Local error in processing. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc == 550) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: RETR failed, trying LIST instead");
+
+ /* Directory Listings should always be fetched in ASCII mode */
+ dirlisting = 1;
+ ftp_set_TYPE('A', r, origin, bb, NULL);
+
+ rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
+ ftp_escape_globbingchars(p, path), CRLF, NULL),
+ r, origin, bb, &ftpmessage);
+ /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+ /* 250 Requested file action okay, completed. */
+ /* 421 Service not available, closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ /* 501 Syntax error in parameters or arguments. */
+ /* 502 Command not implemented. */
+ /* 530 Not logged in. */
+ /* 550 Requested action not taken. */
+ if (rc == -1 || rc == 421) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc == 550) {
+ return ap_proxyerror(r, HTTP_NOT_FOUND, ftpmessage);
+ }
+ if (rc != 250) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+
+ /* Update current directory after CWD */
+ cwd = ftp_get_PWD(r, origin, bb);
+ if (cwd != NULL) {
+ apr_table_set(r->notes, "Directory-PWD", cwd);
+ }
+
+ /* See above for the "LIST" vs. "LIST -lag" discussion. */
+ rc = proxy_ftp_command((cwd == NULL || strchr(cwd, '/') != NULL)
+ ? "LIST -lag" CRLF : "LIST" CRLF,
+ r, origin, bb, &ftpmessage);
+
+ /* rc is an intermediate response for the LIST command (125 transfer starting, 150 opening data connection) */
+ if (rc == -1 || rc == 421)
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+ if (rc != 125 && rc != 150 && rc != 226 && rc != 250) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY, ftpmessage);
+ }
+
+ r->status = HTTP_OK;
+ r->status_line = "200 OK";
+
+ apr_rfc822_date(dates, r->request_time);
+ apr_table_setn(r->headers_out, "Date", dates);
+ apr_table_setn(r->headers_out, "Server", ap_get_server_version());
+
+ /* set content-type */
+ if (dirlisting) {
+ ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ }
+ else {
+ if (r->content_type) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: Content-Type set to %s", r->content_type);
+ }
+ else {
+ ap_set_content_type(r, ap_default_type(r));
+ }
+ if (xfer_type != 'A' && size != NULL) {
+ /* We "trust" the ftp server to really serve (size) bytes... */
+ apr_table_setn(r->headers_out, "Content-Length", size);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: Content-Length set to %s", size);
+ }
+ }
+ apr_table_setn(r->headers_out, "Content-Type", r->content_type);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: Content-Type set to %s", r->content_type);
+
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+ if (mtime != 0L) {
+ char datestr[APR_RFC822_DATE_LEN];
+ apr_rfc822_date(datestr, mtime);
+ apr_table_set(r->headers_out, "Last-Modified", datestr);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: Last-Modified set to %s", datestr);
+ }
+#endif /* USE_MDTM */
+
+ /* If an encoding has been set by mistake, delete it.
+ * @@@ FIXME (e.g., for ftp://user@host/file*.tar.gz,
+ * @@@ the encoding is currently set to x-gzip)
+ */
+ if (dirlisting && r->content_encoding != NULL)
+ r->content_encoding = NULL;
+
+ /* set content-encoding (not for dir listings, they are uncompressed)*/
+ if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: Content-Encoding set to %s", r->content_encoding);
+ apr_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
+ }
+
+ /* wait for connection */
+ if (use_port) {
+ for (;;) {
+ rv = apr_accept(&data_sock, local_sock, r->pool);
+ if (rv == APR_EINTR) {
+ continue;
+ }
+ else if (rv == APR_SUCCESS) {
+ break;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "proxy: FTP: failed to accept data connection");
+ return HTTP_BAD_GATEWAY;
+ }
+ }
+ }
+
+ /* the transfer socket is now open, create a new connection */
+ data = ap_run_create_connection(p, r->server, data_sock, r->connection->id,
+ r->connection->sbh, c->bucket_alloc);
+ if (!data) {
+ /*
+ * the peer reset the connection already; ap_run_create_connection() closed
+ * the socket
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: an error occurred creating the transfer connection");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* set up the connection filters */
+ rc = ap_run_pre_connection(data, data_sock);
+ if (rc != OK && rc != DONE) {
+ data->aborted = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: pre_connection setup failed (%d)",
+ rc);
+ return rc;
+ }
+
+ /*
+ * VI: Receive the Response ------------------------
+ *
+ * Get response from the remote ftp socket, and pass it up the filter chain.
+ */
+
+ /* send response */
+ r->sent_bodyct = 1;
+
+ if (dirlisting) {
+ /* insert directory filter */
+ ap_add_output_filter("PROXY_SEND_DIR", NULL, r, r->connection);
+ }
+
+ /* send body */
+ if (!r->header_only) {
+ apr_bucket *e;
+ int finish = FALSE;
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: start body send");
+
+ /* read the body, pass it to the output filters */
+ while (ap_get_brigade(data->input_filters,
+ bb,
+ AP_MODE_READBYTES,
+ APR_BLOCK_READ,
+ conf->io_buffer_size) == APR_SUCCESS) {
+#if DEBUGGING
+ {
+ apr_off_t readbytes;
+ apr_brigade_length(bb, 0, &readbytes);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ r->server, "proxy (PID %d): readbytes: %#x",
+ getpid(), readbytes);
+ }
+#endif
+ /* sanity check */
+ if (APR_BRIGADE_EMPTY(bb)) {
+ apr_brigade_cleanup(bb);
+ break;
+ }
+
+ /* found the last brigade? */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+ /* if this is the last brigade, cleanup the
+ * backend connection first to prevent the
+ * backend server from hanging around waiting
+ * for a slow client to eat these bytes
+ */
+ ap_flush_conn(data);
+ if (data_sock) {
+ apr_socket_close(data_sock);
+ }
+ data_sock = NULL;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: data connection closed");
+ /* signal that we must leave */
+ finish = TRUE;
+ }
+
+ /* if no EOS yet, then we must flush */
+ if (FALSE == finish) {
+ e = apr_bucket_flush_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ }
+
+ /* try send what we read */
+ if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS
+ || c->aborted) {
+ /* Ack! Phbtt! Die! User aborted! */
+ finish = TRUE;
+ }
+
+ /* make sure we always clean up after ourselves */
+ apr_brigade_cleanup(bb);
+
+ /* if we are done, leave */
+ if (TRUE == finish) {
+ break;
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: end body send");
+
+ }
+ if (data_sock) {
+ ap_flush_conn(data);
+ apr_socket_close(data_sock);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: FTP: data connection closed");
+ }
+
+ /* Retrieve the final response for the RETR or LIST commands */
+ rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage);
+ apr_brigade_cleanup(bb);
+
+ /*
+ * VII: Clean Up -------------
+ *
+ * If there are no KeepAlives, or if the connection has been signalled to
+ * close, close the socket and clean up
+ */
+
+ /* finish */
+ rc = proxy_ftp_command("QUIT" CRLF,
+ r, origin, bb, &ftpmessage);
+ /* responses: 221, 500 */
+ /* 221 Service closing control connection. */
+ /* 500 Syntax error, command unrecognized. */
+ ap_flush_conn(origin);
+ if (origin_sock) {
+ apr_socket_close(origin_sock);
+ origin_sock = NULL;
+ }
+ apr_brigade_destroy(bb);
+ return OK;
+}
+
+static void ap_proxy_ftp_register_hook(apr_pool_t *p)
+{
+ /* hooks */
+ proxy_hook_scheme_handler(ap_proxy_ftp_handler, NULL, NULL, APR_HOOK_MIDDLE);
+ proxy_hook_canon_handler(ap_proxy_ftp_canon, NULL, NULL, APR_HOOK_MIDDLE);
+ /* filters */
+ ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter,
+ NULL, AP_FTYPE_RESOURCE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command apr_table_t */
+ ap_proxy_ftp_register_hook /* register hooks */
+};
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/proxy_http.c b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_http.c
new file mode 100644
index 00000000..ca5f038b
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_http.c
@@ -0,0 +1,1824 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* HTTP routines for Apache proxy */
+
+#include "mod_proxy.h"
+
+module AP_MODULE_DECLARE_DATA proxy_http_module;
+
+int ap_proxy_http_canon(request_rec *r, char *url);
+int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyname,
+ apr_port_t proxyport);
+
+typedef struct {
+ const char *name;
+ apr_port_t port;
+ apr_sockaddr_t *addr;
+ apr_socket_t *sock;
+ int close;
+} proxy_http_conn_t;
+
+static apr_status_t ap_proxy_http_cleanup(request_rec *r,
+ proxy_http_conn_t *p_conn,
+ proxy_conn_rec *backend);
+
+/*
+ * Canonicalise http-like URLs.
+ * scheme is the scheme for the URL
+ * url is the URL starting with the first '/'
+ * def_port is the default port for this scheme.
+ */
+int ap_proxy_http_canon(request_rec *r, char *url)
+{
+ char *host, *path, *search, sport[7];
+ const char *err;
+ const char *scheme;
+ apr_port_t port, def_port;
+
+ /* ap_port_of_scheme() */
+ if (strncasecmp(url, "http:", 5) == 0) {
+ url += 5;
+ scheme = "http";
+ }
+ else if (strncasecmp(url, "https:", 6) == 0) {
+ url += 6;
+ scheme = "https";
+ }
+ else {
+ return DECLINED;
+ }
+ def_port = apr_uri_port_of_scheme(scheme);
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTP: canonicalising URL %s", url);
+
+ /* do syntatic check.
+ * We break the URL into host, port, path, search
+ */
+ port = def_port;
+ err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
+ if (err) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "error parsing URL %s: %s",
+ url, err);
+ return HTTP_BAD_REQUEST;
+ }
+
+ /* now parse path/search args, according to rfc1738 */
+ /* N.B. if this isn't a true proxy request, then the URL _path_
+ * has already been decoded. True proxy requests have r->uri
+ * == r->unparsed_uri, and no others have that property.
+ */
+ if (r->uri == r->unparsed_uri) {
+ search = strchr(url, '?');
+ if (search != NULL)
+ *(search++) = '\0';
+ }
+ else
+ search = r->args;
+
+ /* process path */
+ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
+ if (path == NULL)
+ return HTTP_BAD_REQUEST;
+
+ if (port != def_port)
+ apr_snprintf(sport, sizeof(sport), ":%d", port);
+ else
+ sport[0] = '\0';
+
+ if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
+ host = apr_pstrcat(r->pool, "[", host, "]", NULL);
+ }
+ r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
+ "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
+ return OK;
+}
+
+static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
+{
+ struct proxy_alias *ent;
+ int i, l1, l2;
+ char *u;
+
+ /* XXX FIXME: Make sure this handled the ambiguous case of the :80
+ * after the hostname */
+
+ l1 = strlen(url);
+ ent = (struct proxy_alias *)conf->raliases->elts;
+ for (i = 0; i < conf->raliases->nelts; i++) {
+ l2 = strlen(ent[i].real);
+ if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) {
+ u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+ return ap_construct_url(r->pool, u, r);
+ }
+ }
+ return url;
+}
+
+/* Clear all connection-based headers from the incoming headers table */
+static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
+{
+ const char *name;
+ char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
+
+ apr_table_unset(headers, "Proxy-Connection");
+ if (!next)
+ return;
+
+ while (*next) {
+ name = next;
+ while (*next && !apr_isspace(*next) && (*next != ',')) {
+ ++next;
+ }
+ while (*next && (apr_isspace(*next) || (*next == ','))) {
+ *next = '\0';
+ ++next;
+ }
+ apr_table_unset(headers, name);
+ }
+ apr_table_unset(headers, "Connection");
+}
+
+static
+apr_status_t ap_proxy_http_determine_connection(apr_pool_t *p, request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *c,
+ proxy_server_conf *conf,
+ apr_uri_t *uri,
+ char **url,
+ const char *proxyname,
+ apr_port_t proxyport,
+ char *server_portstr,
+ int server_portstr_size) {
+ int server_port;
+ apr_status_t err;
+ apr_sockaddr_t *uri_addr;
+ /*
+ * Break up the URL to determine the host to connect to
+ */
+
+ /* we break the URL into host, port, uri */
+ if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ apr_pstrcat(p,"URI cannot be parsed: ", *url,
+ NULL));
+ }
+ if (!uri->port) {
+ uri->port = apr_uri_port_of_scheme(uri->scheme);
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTP connecting %s to %s:%d", *url, uri->hostname,
+ uri->port);
+
+ /* do a DNS lookup for the destination host */
+ /* see memory note above */
+ err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri->hostname),
+ APR_UNSPEC, uri->port, 0, c->pool);
+
+ /* allocate these out of the connection pool - the check on
+ * r->connection->id makes sure that this string does not get accessed
+ * past the connection lifetime */
+ /* are we connecting directly, or via a proxy? */
+ if (proxyname) {
+ p_conn->name = apr_pstrdup(c->pool, proxyname);
+ p_conn->port = proxyport;
+ /* see memory note above */
+ err = apr_sockaddr_info_get(&p_conn->addr, p_conn->name, APR_UNSPEC,
+ p_conn->port, 0, c->pool);
+ } else {
+ p_conn->name = apr_pstrdup(c->pool, uri->hostname);
+ p_conn->port = uri->port;
+ p_conn->addr = uri_addr;
+ *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
+ uri->query ? uri->query : "",
+ uri->fragment ? "#" : "",
+ uri->fragment ? uri->fragment : "", NULL);
+ }
+
+ if (err != APR_SUCCESS) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ apr_pstrcat(p, "DNS lookup failure for: ",
+ p_conn->name, NULL));
+ }
+
+ /* Get the server port for the Via headers */
+ {
+ server_port = ap_get_server_port(r);
+ if (ap_is_default_port(server_port, r)) {
+ strcpy(server_portstr,"");
+ } else {
+ apr_snprintf(server_portstr, server_portstr_size, ":%d",
+ server_port);
+ }
+ }
+
+ /* check if ProxyBlock directive on this host */
+ if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
+ }
+ return OK;
+}
+
+static
+apr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *c, conn_rec **origin,
+ proxy_conn_rec *backend,
+ proxy_server_conf *conf,
+ const char *proxyname) {
+ int failed=0, new=0;
+ apr_socket_t *client_socket = NULL;
+
+ /* We have determined who to connect to. Now make the connection, supporting
+ * a KeepAlive connection.
+ */
+
+ /* get all the possible IP addresses for the destname and loop through them
+ * until we get a successful connection
+ */
+
+ /* if a keepalive socket is already open, check whether it must stay
+ * open, or whether it should be closed and a new socket created.
+ */
+ /* see memory note above */
+ if (backend->connection) {
+ client_socket = ap_get_module_config(backend->connection->conn_config, &core_module);
+ if ((backend->connection->id == c->id) &&
+ (backend->port == p_conn->port) &&
+ (backend->hostname) &&
+ (!apr_strnatcasecmp(backend->hostname, p_conn->name))) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: keepalive address match (keep original socket)");
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: keepalive address mismatch / connection has"
+ " changed (close old socket (%s/%s, %d/%d))",
+ p_conn->name, backend->hostname, p_conn->port,
+ backend->port);
+ apr_socket_close(client_socket);
+ backend->connection = NULL;
+ }
+ }
+
+ /* get a socket - either a keepalive one, or a new one */
+ new = 1;
+ if ((backend->connection) && (backend->connection->id == c->id)) {
+ apr_size_t buffer_len = 1;
+ char test_buffer[1];
+ apr_status_t socket_status;
+ apr_interval_time_t current_timeout;
+
+ /* use previous keepalive socket */
+ *origin = backend->connection;
+ p_conn->sock = client_socket;
+ new = 0;
+
+ /* save timeout */
+ apr_socket_timeout_get(p_conn->sock, &current_timeout);
+ /* set no timeout */
+ apr_socket_timeout_set(p_conn->sock, 0);
+ socket_status = apr_recv(p_conn->sock, test_buffer, &buffer_len);
+ /* put back old timeout */
+ apr_socket_timeout_set(p_conn->sock, current_timeout);
+ if ( APR_STATUS_IS_EOF(socket_status) ) {
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL,
+ "proxy: previous connection is closed, creating a new connection.");
+ new = 1;
+ }
+ }
+ if (new) {
+ int rc;
+
+ /* create a new socket */
+ backend->connection = NULL;
+
+ /*
+ * At this point we have a list of one or more IP addresses of
+ * the machine to connect to. If configured, reorder this
+ * list so that the "best candidate" is first try. "best
+ * candidate" could mean the least loaded server, the fastest
+ * responding server, whatever.
+ *
+ * For now we do nothing, ie we get DNS round robin.
+ * XXX FIXME
+ */
+ failed = ap_proxy_connect_to_backend(&p_conn->sock, "HTTP",
+ p_conn->addr, p_conn->name,
+ conf, r->server, c->pool);
+
+ /* handle a permanent error on the connect */
+ if (failed) {
+ if (proxyname) {
+ return DECLINED;
+ } else {
+ return HTTP_BAD_GATEWAY;
+ }
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: socket is connected");
+
+ /* the socket is now open, create a new backend server connection */
+ *origin = ap_run_create_connection(c->pool, r->server, p_conn->sock,
+ r->connection->id,
+ r->connection->sbh, c->bucket_alloc);
+ if (!*origin) {
+ /* the peer reset the connection already; ap_run_create_connection()
+ * closed the socket
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ r->server, "proxy: an error occurred creating a "
+ "new connection to %pI (%s)", p_conn->addr,
+ p_conn->name);
+ apr_socket_close(p_conn->sock);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ backend->connection = *origin;
+ backend->hostname = apr_pstrdup(c->pool, p_conn->name);
+ backend->port = p_conn->port;
+
+ if (backend->is_ssl) {
+ if (!ap_proxy_ssl_enable(backend->connection)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+ r->server, "proxy: failed to enable ssl support "
+ "for %pI (%s)", p_conn->addr, p_conn->name);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+ else {
+ ap_proxy_ssl_disable(backend->connection);
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: connection complete to %pI (%s)",
+ p_conn->addr, p_conn->name);
+
+ /* set up the connection filters */
+ rc = ap_run_pre_connection(*origin, p_conn->sock);
+ if (rc != OK && rc != DONE) {
+ (*origin)->aborted = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTP: pre_connection setup failed (%d)",
+ rc);
+ return rc;
+ }
+ }
+ return OK;
+}
+
+static void add_te_chunked(apr_pool_t *p,
+ apr_bucket_alloc_t *bucket_alloc,
+ apr_bucket_brigade *header_brigade)
+{
+ apr_bucket *e;
+ char *buf;
+ const char te_hdr[] = "Transfer-Encoding: chunked" CRLF;
+
+ buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1);
+ ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1);
+
+ e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+}
+
+static void add_cl(apr_pool_t *p,
+ apr_bucket_alloc_t *bucket_alloc,
+ apr_bucket_brigade *header_brigade,
+ const char *cl_val)
+{
+ apr_bucket *e;
+ char *buf;
+
+ buf = apr_pstrcat(p, "Content-Length: ",
+ cl_val,
+ CRLF,
+ NULL);
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+}
+
+#define ASCII_CRLF "\015\012"
+#define ASCII_ZERO "\060"
+
+static void terminate_headers(apr_bucket_alloc_t *bucket_alloc,
+ apr_bucket_brigade *header_brigade)
+{
+ apr_bucket *e;
+
+ /* add empty line at the end of the headers */
+ e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+}
+
+static apr_status_t pass_brigade(apr_bucket_alloc_t *bucket_alloc,
+ request_rec *r, proxy_http_conn_t *p_conn,
+ conn_rec *origin, apr_bucket_brigade *bb,
+ int flush)
+{
+ apr_status_t status;
+
+ if (flush) {
+ apr_bucket *e = apr_bucket_flush_create(bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ }
+ status = ap_pass_brigade(origin->output_filters, bb);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: pass request body failed to %pI (%s)",
+ p_conn->addr, p_conn->name);
+ return status;
+ }
+ apr_brigade_cleanup(bb);
+ return APR_SUCCESS;
+}
+
+static apr_status_t stream_reqbody_chunked(apr_pool_t *p,
+ request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *origin,
+ apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade)
+{
+ int seen_eos = 0;
+ apr_size_t hdr_len;
+ apr_off_t bytes;
+ apr_status_t status;
+ apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
+ apr_bucket_brigade *bb;
+ apr_bucket *e;
+
+ add_te_chunked(p, bucket_alloc, header_brigade);
+ terminate_headers(bucket_alloc, header_brigade);
+
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
+ char chunk_hdr[20]; /* must be here due to transient bucket. */
+
+ /* If this brigade contains EOS, either stop or remove it. */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+ seen_eos = 1;
+
+ /* We can't pass this EOS to the output_filters. */
+ e = APR_BRIGADE_LAST(input_brigade);
+ apr_bucket_delete(e);
+ }
+
+ apr_brigade_length(input_brigade, 1, &bytes);
+
+ hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
+ "%" APR_UINT64_T_HEX_FMT CRLF,
+ (apr_uint64_t)bytes);
+
+ ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
+ e = apr_bucket_transient_create(chunk_hdr, hdr_len,
+ bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(input_brigade, e);
+
+ /*
+ * Append the end-of-chunk CRLF
+ */
+ e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
+
+ if (header_brigade) {
+ /* we never sent the header brigade, so go ahead and
+ * take care of that now
+ */
+ bb = header_brigade;
+
+ /*
+ * Save input_brigade in bb brigade. (At least) in the SSL case
+ * input_brigade contains transient buckets whose data would get
+ * overwritten during the next call of ap_get_brigade in the loop.
+ * ap_save_brigade ensures these buckets to be set aside.
+ * Calling ap_save_brigade with NULL as filter is OK, because
+ * bb brigade already has been created and does not need to get
+ * created by ap_save_brigade.
+ */
+ status = ap_save_brigade(NULL, &bb, &input_brigade, p);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ header_brigade = NULL;
+ }
+ else {
+ bb = input_brigade;
+ }
+
+ /* The request is flushed below this loop with chunk EOS header */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ if (seen_eos) {
+ break;
+ }
+
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ }
+
+ if (header_brigade) {
+ /* we never sent the header brigade because there was no request body;
+ * send it now
+ */
+ bb = header_brigade;
+ }
+ else {
+ if (!APR_BRIGADE_EMPTY(input_brigade)) {
+ /* input brigade still has an EOS which we can't pass to the output_filters. */
+ e = APR_BRIGADE_LAST(input_brigade);
+ AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e));
+ apr_bucket_delete(e);
+ }
+ bb = input_brigade;
+ }
+
+ e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
+ /* <trailers> */
+ ASCII_CRLF,
+ 5, bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+
+ /* Now we have headers-only, or the chunk EOS mark; flush it */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1);
+ return status;
+}
+
+static apr_status_t stream_reqbody_cl(apr_pool_t *p,
+ request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *origin,
+ apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade,
+ const char *old_cl_val)
+{
+ int seen_eos = 0;
+ apr_status_t status = APR_SUCCESS;
+ apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
+ apr_bucket_brigade *bb;
+ apr_bucket *e;
+ apr_off_t cl_val = 0;
+ apr_off_t bytes;
+ apr_off_t bytes_streamed = 0;
+
+ if (old_cl_val) {
+ add_cl(p, bucket_alloc, header_brigade, old_cl_val);
+ cl_val = atol(old_cl_val);
+ }
+ terminate_headers(bucket_alloc, header_brigade);
+
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
+ apr_brigade_length(input_brigade, 1, &bytes);
+ bytes_streamed += bytes;
+
+ /* If this brigade contains EOS, either stop or remove it. */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+ seen_eos = 1;
+
+ /* We can't pass this EOS to the output_filters. */
+ e = APR_BRIGADE_LAST(input_brigade);
+ apr_bucket_delete(e);
+ }
+
+ /* C-L < bytes streamed?!?
+ * We will error out after the body is completely
+ * consumed, but we can't stream more bytes at the
+ * back end since they would in part be interpreted
+ * as another request! If nothing is sent, then
+ * just send nothing.
+ *
+ * Prevents HTTP Response Splitting.
+ */
+ if (bytes_streamed > cl_val)
+ continue;
+
+ if (header_brigade) {
+ /* we never sent the header brigade, so go ahead and
+ * take care of that now
+ */
+ bb = header_brigade;
+
+ /*
+ * Save input_brigade in bb brigade. (At least) in the SSL case
+ * input_brigade contains transient buckets whose data would get
+ * overwritten during the next call of ap_get_brigade in the loop.
+ * ap_save_brigade ensures these buckets to be set aside.
+ * Calling ap_save_brigade with NULL as filter is OK, because
+ * bb brigade already has been created and does not need to get
+ * created by ap_save_brigade.
+ */
+ status = ap_save_brigade(NULL, &bb, &input_brigade, p);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ header_brigade = NULL;
+ }
+ else {
+ bb = input_brigade;
+ }
+
+ /* Once we hit EOS, we are ready to flush. */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ if (seen_eos) {
+ break;
+ }
+
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ }
+
+ if (bytes_streamed != cl_val) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "proxy: client %s given Content-Length did not match"
+ " number of body bytes read", r->connection->remote_ip);
+ return APR_EOF;
+ }
+
+ if (header_brigade) {
+ /* we never sent the header brigade since there was no request
+ * body; send it now with the flush flag
+ */
+ bb = header_brigade;
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1);
+ }
+ return status;
+}
+
+#define MAX_MEM_SPOOL 16384
+
+static apr_status_t spool_reqbody_cl(apr_pool_t *p,
+ request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *origin,
+ apr_bucket_brigade *header_brigade,
+ apr_bucket_brigade *input_brigade,
+ int force_cl)
+{
+ int seen_eos = 0;
+ apr_status_t status;
+ apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc;
+ apr_bucket_brigade *body_brigade;
+ apr_bucket *e;
+ apr_off_t bytes, bytes_spooled = 0, fsize = 0;
+ apr_file_t *tmpfile = NULL;
+
+ body_brigade = apr_brigade_create(p, bucket_alloc);
+
+ while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade)))
+ {
+ /* If this brigade contains EOS, either stop or remove it. */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+ seen_eos = 1;
+
+ /* We can't pass this EOS to the output_filters. */
+ e = APR_BRIGADE_LAST(input_brigade);
+ apr_bucket_delete(e);
+ }
+
+ apr_brigade_length(input_brigade, 1, &bytes);
+
+ if (bytes_spooled + bytes > MAX_MEM_SPOOL) {
+ /* can't spool any more in memory; write latest brigade to disk */
+ if (tmpfile == NULL) {
+ const char *temp_dir;
+ char *template;
+
+ status = apr_temp_dir_get(&temp_dir, p);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: search for temporary directory failed");
+ return status;
+ }
+ apr_filepath_merge(&template, temp_dir,
+ "modproxy.tmp.XXXXXX",
+ APR_FILEPATH_NATIVE, p);
+ status = apr_file_mktemp(&tmpfile, template, 0, p);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: creation of temporary file in directory %s failed",
+ temp_dir);
+ return status;
+ }
+ }
+ for (e = APR_BRIGADE_FIRST(input_brigade);
+ e != APR_BRIGADE_SENTINEL(input_brigade);
+ e = APR_BUCKET_NEXT(e)) {
+ const char *data;
+ apr_size_t bytes_read, bytes_written;
+
+ apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ);
+ status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written);
+ if (status != APR_SUCCESS) {
+ const char *tmpfile_name;
+
+ if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) {
+ tmpfile_name = "(unknown)";
+ }
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: write to temporary file %s failed",
+ tmpfile_name);
+ return status;
+ }
+ AP_DEBUG_ASSERT(bytes_read == bytes_written);
+ fsize += bytes_written;
+ }
+ apr_brigade_cleanup(input_brigade);
+ }
+ else {
+
+ /*
+ * Save input_brigade in body_brigade. (At least) in the SSL case
+ * input_brigade contains transient buckets whose data would get
+ * overwritten during the next call of ap_get_brigade in the loop.
+ * ap_save_brigade ensures these buckets to be set aside.
+ * Calling ap_save_brigade with NULL as filter is OK, because
+ * body_brigade already has been created and does not need to get
+ * created by ap_save_brigade.
+ */
+ status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+
+ }
+
+ bytes_spooled += bytes;
+
+ if (seen_eos) {
+ break;
+ }
+
+ status = ap_get_brigade(r->input_filters, input_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ HUGE_STRING_LEN);
+
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ }
+
+ if (bytes_spooled || force_cl) {
+ add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled));
+ }
+ terminate_headers(bucket_alloc, header_brigade);
+ APR_BRIGADE_CONCAT(header_brigade, body_brigade);
+ if (tmpfile) {
+ /* For platforms where the size of the file may be larger than
+ * that which can be stored in a single bucket (where the
+ * length field is an apr_size_t), split it into several
+ * buckets: */
+ if (sizeof(apr_off_t) > sizeof(apr_size_t)
+ && fsize > AP_MAX_SENDFILE) {
+ e = apr_bucket_file_create(tmpfile, 0, AP_MAX_SENDFILE, p,
+ bucket_alloc);
+ while (fsize > AP_MAX_SENDFILE) {
+ apr_bucket *ce;
+ apr_bucket_copy(e, &ce);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, ce);
+ e->start += AP_MAX_SENDFILE;
+ fsize -= AP_MAX_SENDFILE;
+ }
+ e->length = (apr_size_t)fsize; /* Resize just the last bucket */
+ }
+ else {
+ e = apr_bucket_file_create(tmpfile, 0, (apr_size_t)fsize, p,
+ bucket_alloc);
+ }
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
+ /* This is all a single brigade, pass with flush flagged */
+ status = pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1);
+ return status;
+}
+
+static
+apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
+ proxy_http_conn_t *p_conn, conn_rec *origin,
+ proxy_server_conf *conf,
+ apr_uri_t *uri,
+ char *url,
+ apr_bucket_brigade *header_brigade,
+ char *server_portstr)
+{
+ conn_rec *c = r->connection;
+ apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc;
+ apr_bucket_brigade *input_brigade;
+ apr_bucket_brigade *temp_brigade;
+ apr_bucket *e;
+ char *buf;
+ const apr_array_header_t *headers_in_array;
+ const apr_table_entry_t *headers_in;
+ int counter;
+ apr_status_t status;
+ enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL};
+ enum rb_methods rb_method = RB_INIT;
+ const char *old_cl_val = NULL;
+ const char *old_te_val = NULL;
+ apr_off_t bytes_read = 0;
+ apr_off_t bytes;
+ int force10;
+
+ /*
+ * Send the HTTP/1.1 request to the remote server
+ */
+
+ /* strip connection listed hop-by-hop headers from the request */
+ /* even though in theory a connection: close coming from the client
+ * should not affect the connection to the server, it's unlikely
+ * that subsequent client requests will hit this thread/process,
+ * so we cancel server keepalive if the client does.
+ */
+ if (ap_proxy_liststr(apr_table_get(r->headers_in,
+ "Connection"), "close")) {
+ p_conn->close++;
+ /* XXX: we are abusing r->headers_in rather than a copy,
+ * give the core output handler a clue the client would
+ * rather just close.
+ */
+ c->keepalive = AP_CONN_CLOSE;
+ }
+ ap_proxy_clear_connection(p, r->headers_in);
+
+ if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
+ buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
+ force10 = 1;
+ p_conn->close++;
+ } else {
+ buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
+ force10 = 0;
+ }
+ if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
+ origin->keepalive = AP_CONN_CLOSE;
+ p_conn->close++;
+ }
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ if (conf->preserve_host == 0) {
+ if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
+ buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
+ CRLF, NULL);
+ } else {
+ buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
+ }
+ }
+ else {
+ /* don't want to use r->hostname, as the incoming header might have a
+ * port attached
+ */
+ const char* hostname = apr_table_get(r->headers_in,"Host");
+ if (!hostname) {
+ hostname = r->server->server_hostname;
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "proxy: no HTTP 0.9 request (with no host line) "
+ "on incoming request and preserve host set "
+ "forcing hostname to be %s for uri %s",
+ hostname,
+ r->uri );
+ }
+ buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
+ }
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+
+ /* handle Via */
+ if (conf->viaopt == via_block) {
+ /* Block all outgoing Via: headers */
+ apr_table_unset(r->headers_in, "Via");
+ } else if (conf->viaopt != via_off) {
+ const char *server_name = ap_get_server_name(r);
+ /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
+ * then the server name returned by ap_get_server_name() is the
+ * origin server name (which does make too much sense with Via: headers)
+ * so we use the proxy vhost's name instead.
+ */
+ if (server_name == r->hostname)
+ server_name = r->server->server_hostname;
+ /* Create a "Via:" request header entry and merge it */
+ /* Generate outgoing Via: header with/without server comment: */
+ apr_table_mergen(r->headers_in, "Via",
+ (conf->viaopt == via_full)
+ ? apr_psprintf(p, "%d.%d %s%s (%s)",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ server_name, server_portstr,
+ AP_SERVER_BASEVERSION)
+ : apr_psprintf(p, "%d.%d %s%s",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ server_name, server_portstr)
+ );
+ }
+
+ /* X-Forwarded-*: handling
+ *
+ * XXX Privacy Note:
+ * -----------------
+ *
+ * These request headers are only really useful when the mod_proxy
+ * is used in a reverse proxy configuration, so that useful info
+ * about the client can be passed through the reverse proxy and on
+ * to the backend server, which may require the information to
+ * function properly.
+ *
+ * In a forward proxy situation, these options are a potential
+ * privacy violation, as information about clients behind the proxy
+ * are revealed to arbitrary servers out there on the internet.
+ *
+ * The HTTP/1.1 Via: header is designed for passing client
+ * information through proxies to a server, and should be used in
+ * a forward proxy configuation instead of X-Forwarded-*. See the
+ * ProxyVia option for details.
+ */
+
+ if (PROXYREQ_REVERSE == r->proxyreq) {
+ const char *buf;
+
+ /* Add X-Forwarded-For: so that the upstream has a chance to
+ * determine, where the original request came from.
+ */
+ apr_table_mergen(r->headers_in, "X-Forwarded-For",
+ r->connection->remote_ip);
+
+ /* Add X-Forwarded-Host: so that upstream knows what the
+ * original request hostname was.
+ */
+ if ((buf = apr_table_get(r->headers_in, "Host"))) {
+ apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
+ }
+
+ /* Add X-Forwarded-Server: so that upstream knows what the
+ * name of this proxy server is (if there are more than one)
+ * XXX: This duplicates Via: - do we strictly need it?
+ */
+ apr_table_mergen(r->headers_in, "X-Forwarded-Server",
+ r->server->server_hostname);
+ }
+
+ /* send request headers */
+ proxy_run_fixups(r);
+ headers_in_array = apr_table_elts(r->headers_in);
+ headers_in = (const apr_table_entry_t *) headers_in_array->elts;
+ for (counter = 0; counter < headers_in_array->nelts; counter++) {
+ if (headers_in[counter].key == NULL
+ || headers_in[counter].val == NULL
+
+ /* Already sent */
+ || !strcasecmp(headers_in[counter].key, "Host")
+
+ /* Clear out hop-by-hop request headers not to send
+ * RFC2616 13.5.1 says we should strip these headers
+ */
+ || !strcasecmp(headers_in[counter].key, "Keep-Alive")
+ || !strcasecmp(headers_in[counter].key, "TE")
+ || !strcasecmp(headers_in[counter].key, "Trailer")
+ || !strcasecmp(headers_in[counter].key, "Upgrade")
+
+ /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
+ * suppressed if THIS server requested the authentication,
+ * not when a frontend proxy requested it!
+ *
+ * The solution to this problem is probably to strip out
+ * the Proxy-Authorisation header in the authorisation
+ * code itself, not here. This saves us having to signal
+ * somehow whether this request was authenticated or not.
+ */
+ || !strcasecmp(headers_in[counter].key,"Proxy-Authorization")
+ || !strcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
+ continue;
+ }
+
+ /* Skip Transfer-Encoding and Content-Length for now.
+ */
+ if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
+ old_te_val = headers_in[counter].val;
+ continue;
+ }
+ if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
+ old_cl_val = headers_in[counter].val;
+ continue;
+ }
+
+ /* for sub-requests, ignore freshness/expiry headers */
+ if (r->main) {
+ if ( !strcasecmp(headers_in[counter].key, "If-Match")
+ || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
+ || !strcasecmp(headers_in[counter].key, "If-Range")
+ || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
+ || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
+ continue;
+ }
+ }
+
+ buf = apr_pstrcat(p, headers_in[counter].key, ": ",
+ headers_in[counter].val, CRLF,
+ NULL);
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
+
+ /* We have headers, let's figure out our request body... */
+ input_brigade = apr_brigade_create(p, bucket_alloc);
+
+ /* sub-requests never use keepalives, and mustn't pass request bodies.
+ * Because the new logic looks at input_brigade, we will self-terminate
+ * input_brigade and jump past all of the request body logic...
+ * Reading anything with ap_get_brigade is likely to consume the
+ * main request's body or read beyond EOS - which would be unplesant.
+ */
+ if (r->main) {
+ p_conn->close++;
+ if (old_cl_val) {
+ old_cl_val = NULL;
+ apr_table_unset(r->headers_in, "Content-Length");
+ }
+ if (old_te_val) {
+ old_te_val = NULL;
+ apr_table_unset(r->headers_in, "Transfer-Encoding");
+ }
+ rb_method = RB_STREAM_CL;
+ e = apr_bucket_eos_create(input_brigade->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(input_brigade, e);
+ goto skip_body;
+ }
+
+ /* WE only understand chunked. Other modules might inject
+ * (and therefore, decode) other flavors but we don't know
+ * that the can and have done so unless they they remove
+ * their decoding from the headers_in T-E list.
+ * XXX: Make this extensible, but in doing so, presume the
+ * encoding has been done by the extensions' handler, and
+ * do not modify add_te_chunked's logic
+ */
+ if (old_te_val && strcmp(old_te_val, "chunked") != 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "proxy: %s Transfer-Encoding is not supported",
+ old_te_val);
+ return APR_EINVAL;
+ }
+
+ if (old_cl_val && old_te_val) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_ENOTIMPL, r->server,
+ "proxy: client %s (%s) requested Transfer-Encoding body"
+ " with Content-Length (C-L ignored)",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ apr_table_unset(r->headers_in, "Content-Length");
+ old_cl_val = NULL;
+ origin->keepalive = AP_CONN_CLOSE;
+ p_conn->close++;
+ }
+
+ /* Prefetch MAX_MEM_SPOOL bytes
+ *
+ * This helps us avoid any election of C-L v.s. T-E
+ * request bodies, since we are willing to keep in
+ * memory this much data, in any case. This gives
+ * us an instant C-L election if the body is of some
+ * reasonable size.
+ */
+ temp_brigade = apr_brigade_create(p, bucket_alloc);
+ do {
+ status = ap_get_brigade(r->input_filters, temp_brigade,
+ AP_MODE_READBYTES, APR_BLOCK_READ,
+ MAX_MEM_SPOOL - bytes_read);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: prefetch request body failed to %s"
+ " from %s (%s)",
+ p_conn->name ? p_conn->name: "",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ return status;
+ }
+
+ apr_brigade_length(temp_brigade, 1, &bytes);
+ bytes_read += bytes;
+
+ /*
+ * Save temp_brigade in input_brigade. (At least) in the SSL case
+ * temp_brigade contains transient buckets whose data would get
+ * overwritten during the next call of ap_get_brigade in the loop.
+ * ap_save_brigade ensures these buckets to be set aside.
+ * Calling ap_save_brigade with NULL as filter is OK, because
+ * input_brigade already has been created and does not need to get
+ * created by ap_save_brigade.
+ */
+ status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p);
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: processing prefetched request body failed"
+ " to %s from %s (%s)",
+ p_conn->name ? p_conn->name: "",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ return status;
+ }
+
+ /* Ensure we don't hit a wall where we have a buffer too small
+ * for ap_get_brigade's filters to fetch us another bucket,
+ * surrender once we hit 80 bytes less than MAX_MEM_SPOOL
+ * (an arbitrary value.)
+ */
+ } while ((bytes_read < MAX_MEM_SPOOL - 80)
+ && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)));
+
+ /* Use chunked request body encoding or send a content-length body?
+ *
+ * Prefer C-L when:
+ *
+ * We have no request body (handled by RB_STREAM_CL)
+ *
+ * We have a request body length <= MAX_MEM_SPOOL
+ *
+ * The administrator has setenv force-proxy-request-1.0
+ *
+ * The client sent a C-L body, and the administrator has
+ * not setenv proxy-sendchunked or has set setenv proxy-sendcl
+ *
+ * The client sent a T-E body, and the administrator has
+ * setenv proxy-sendcl, and not setenv proxy-sendchunked
+ *
+ * If both proxy-sendcl and proxy-sendchunked are set, the
+ * behavior is the same as if neither were set, large bodies
+ * that can't be read will be forwarded in their original
+ * form of C-L, or T-E.
+ *
+ * To ensure maximum compatibility, setenv proxy-sendcl
+ * To reduce server resource use, setenv proxy-sendchunked
+ *
+ * Then address specific servers with conditional setenv
+ * options to restore the default behavior where desireable.
+ *
+ * We have to compute content length by reading the entire request
+ * body; if request body is not small, we'll spool the remaining
+ * input to a temporary file. Chunked is always preferable.
+ *
+ * We can only trust the client-provided C-L if the T-E header
+ * is absent, and the filters are unchanged (the body won't
+ * be resized by another content filter).
+ */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+ /* The whole thing fit, so our decision is trivial, use
+ * the filtered bytes read from the client for the request
+ * body Content-Length.
+ *
+ * If we expected no body, and read no body, do not set
+ * the Content-Length.
+ */
+ if (old_cl_val || old_te_val || bytes_read) {
+ old_cl_val = apr_off_t_toa(r->pool, bytes_read);
+ }
+ rb_method = RB_STREAM_CL;
+ }
+ else if (old_te_val) {
+ if (force10
+ || (apr_table_get(r->subprocess_env, "proxy-sendcl")
+ && !apr_table_get(r->subprocess_env, "proxy-sendchunks")
+ && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) {
+ rb_method = RB_SPOOL_CL;
+ }
+ else {
+ rb_method = RB_STREAM_CHUNKED;
+ }
+ }
+ else if (old_cl_val) {
+ if (r->input_filters == r->proto_input_filters) {
+ rb_method = RB_STREAM_CL;
+ }
+ else if (!force10
+ && (apr_table_get(r->subprocess_env, "proxy-sendchunks")
+ || apr_table_get(r->subprocess_env, "proxy-sendchunked"))
+ && !apr_table_get(r->subprocess_env, "proxy-sendcl")) {
+ rb_method = RB_STREAM_CHUNKED;
+ }
+ else {
+ rb_method = RB_SPOOL_CL;
+ }
+ }
+ else {
+ /* This is an appropriate default; very efficient for no-body
+ * requests, and has the behavior that it will not add any C-L
+ * when the old_cl_val is NULL.
+ */
+ rb_method = RB_SPOOL_CL;
+ }
+
+/* Yes I hate gotos. This is the subrequest shortcut */
+skip_body:
+ /* Handle Connection: header */
+ if (!force10 && p_conn->close) {
+ buf = apr_pstrdup(p, "Connection: close" CRLF);
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
+
+ /* send the request body, if any. */
+ switch(rb_method) {
+ case RB_STREAM_CHUNKED:
+ status = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade,
+ input_brigade);
+ break;
+ case RB_STREAM_CL:
+ status = stream_reqbody_cl(p, r, p_conn, origin, header_brigade,
+ input_brigade, old_cl_val);
+ break;
+ case RB_SPOOL_CL:
+ status = spool_reqbody_cl(p, r, p_conn, origin, header_brigade,
+ input_brigade, (old_cl_val != NULL)
+ || (old_te_val != NULL)
+ || (bytes_read > 0));
+ break;
+ default:
+ ap_assert(1 != 1);
+ break;
+ }
+
+ if (status != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+ "proxy: pass request body failed to %pI (%s)"
+ " from %s (%s)",
+ p_conn->addr, p_conn->name ? p_conn->name: "",
+ c->remote_ip, c->remote_host ? c->remote_host: "");
+ return status;
+ }
+
+ return APR_SUCCESS;
+}
+
+static int addit_dammit(void *v, const char *key, const char *val)
+{
+ apr_table_addn(v, key, val);
+ return 1;
+}
+
+/*
+ * Limit the number of interim respones we sent back to the client. Otherwise
+ * we suffer from a memory build up. Besides there is NO sense in sending back
+ * an unlimited number of interim responses to the client. Thus if we cross
+ * this limit send back a 502 (Bad Gateway).
+ */
+#ifndef AP_MAX_INTERIM_RESPONSES
+#define AP_MAX_INTERIM_RESPONSES 10
+#endif
+
+static
+apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
+ proxy_http_conn_t *p_conn,
+ conn_rec *origin,
+ proxy_conn_rec *backend,
+ proxy_server_conf *conf,
+ apr_bucket_brigade *bb,
+ char *server_portstr) {
+ conn_rec *c = r->connection;
+ char buffer[HUGE_STRING_LEN];
+ const char *buf;
+ char keepchar;
+ request_rec *rp;
+ apr_bucket *e;
+ apr_table_t *save_table;
+ int len, backasswards;
+ int received_continue = 1; /* flag to indicate if we should
+ * loop over response parsing logic
+ * in the case that the origin told us
+ * to HTTP_CONTINUE
+ */
+
+ /* Get response from the remote server, and pass it up the
+ * filter chain
+ */
+
+ rp = ap_proxy_make_fake_req(origin, r);
+ /* In case anyone needs to know, this is a fake request that is really a
+ * response.
+ */
+ rp->proxyreq = PROXYREQ_RESPONSE;
+
+ while (received_continue && (received_continue <= AP_MAX_INTERIM_RESPONSES)) {
+ apr_brigade_cleanup(bb);
+
+ len = ap_getline(buffer, sizeof(buffer), rp, 0);
+ if (len == 0) {
+ /* handle one potential stray CRLF */
+ len = ap_getline(buffer, sizeof(buffer), rp, 0);
+ }
+ if (len <= 0) {
+ apr_socket_close(p_conn->sock);
+ backend->connection = NULL;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: error reading status line from remote "
+ "server %s", p_conn->name);
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ "Error reading from remote server");
+ }
+
+ /* Is it an HTTP/1 response?
+ * This is buggy if we ever see an HTTP/1.10
+ */
+ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+ int major, minor;
+
+ if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
+ major = 1;
+ minor = 1;
+ }
+ /* If not an HTTP/1 message or
+ * if the status line was > 8192 bytes
+ */
+ else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
+ apr_socket_close(p_conn->sock);
+ backend->connection = NULL;
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ apr_pstrcat(p, "Corrupt status line returned by remote "
+ "server: ", buffer, NULL));
+ }
+ backasswards = 0;
+
+ keepchar = buffer[12];
+ buffer[12] = '\0';
+ r->status = atoi(&buffer[9]);
+
+ if (keepchar != '\0') {
+ buffer[12] = keepchar;
+ } else {
+ /* 2616 requires the space in Status-Line; the origin
+ * server may have sent one but ap_rgetline_core will
+ * have stripped it. */
+ buffer[12] = ' ';
+ buffer[13] = '\0';
+ }
+ r->status_line = apr_pstrdup(p, &buffer[9]);
+
+ /* read the headers. */
+ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/
+ /* Also, take care with headers with multiple occurences. */
+
+ /* First, tuck away all already existing cookies */
+ save_table = apr_table_make(r->pool, 2);
+ apr_table_do(addit_dammit, save_table, r->headers_out,
+ "Set-Cookie", NULL);
+
+ r->headers_out = ap_proxy_read_headers(r, rp, buffer,
+ sizeof(buffer), origin);
+ if (r->headers_out == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
+ r->server, "proxy: bad HTTP/%d.%d header "
+ "returned by %s (%s)", major, minor, r->uri,
+ r->method);
+ p_conn->close += 1;
+ /*
+ * ap_send_error relies on a headers_out to be present. we
+ * are in a bad position here.. so force everything we send out
+ * to have nothing to do with the incoming packet
+ */
+ r->headers_out = apr_table_make(r->pool,1);
+ r->status = HTTP_BAD_GATEWAY;
+ r->status_line = "bad gateway";
+ return r->status;
+ }
+
+ /* Now, add in the just read cookies */
+ apr_table_do(addit_dammit, save_table, r->headers_out,
+ "Set-Cookie", NULL);
+
+ /* and now load 'em all in */
+ if (!apr_is_empty_table(save_table)) {
+ apr_table_unset(r->headers_out, "Set-Cookie");
+ r->headers_out = apr_table_overlay(r->pool,
+ r->headers_out,
+ save_table);
+ }
+
+ /* can't have both Content-Length and Transfer-Encoding */
+ if (apr_table_get(r->headers_out, "Transfer-Encoding")
+ && apr_table_get(r->headers_out, "Content-Length")) {
+ /* 2616 section 4.4, point 3: "if both Transfer-Encoding
+ * and Content-Length are received, the latter MUST be
+ * ignored"; so unset it here to prevent any confusion
+ * later. */
+ apr_table_unset(r->headers_out, "Content-Length");
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ r->server,
+ "proxy: server %s returned Transfer-Encoding and Content-Length",
+ p_conn->name);
+ p_conn->close += 1;
+ }
+
+ /* strip connection listed hop-by-hop headers from response */
+ p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
+ "Connection"),
+ "close");
+ ap_proxy_clear_connection(p, r->headers_out);
+ if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+ ap_set_content_type(r, apr_pstrdup(p, buf));
+ }
+ if (!ap_is_HTTP_INFO(r->status)) {
+ ap_proxy_pre_http_request(origin, rp);
+ }
+
+ /* handle Via header in response */
+ if (conf->viaopt != via_off && conf->viaopt != via_block) {
+ const char *server_name = ap_get_server_name(r);
+ /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
+ * then the server name returned by ap_get_server_name() is the
+ * origin server name (which does make too much sense with Via: headers)
+ * so we use the proxy vhost's name instead.
+ */
+ if (server_name == r->hostname)
+ server_name = r->server->server_hostname;
+
+ /* create a "Via:" response header entry and merge it */
+ apr_table_mergen(r->headers_out, "Via",
+ (conf->viaopt == via_full)
+ ? apr_psprintf(p, "%d.%d %s%s (%s)",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ server_name,
+ server_portstr,
+ AP_SERVER_BASEVERSION)
+ : apr_psprintf(p, "%d.%d %s%s",
+ HTTP_VERSION_MAJOR(r->proto_num),
+ HTTP_VERSION_MINOR(r->proto_num),
+ server_name,
+ server_portstr)
+ );
+ }
+
+ /* cancel keepalive if HTTP/1.0 or less */
+ if ((major < 1) || (minor < 1)) {
+ p_conn->close += 1;
+ origin->keepalive = AP_CONN_CLOSE;
+ }
+ } else {
+ /* an http/0.9 response */
+ backasswards = 1;
+ r->status = 200;
+ r->status_line = "200 OK";
+ p_conn->close += 1;
+ }
+
+ if ( r->status != HTTP_CONTINUE ) {
+ received_continue = 0;
+ } else {
+ received_continue++;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+ "proxy: HTTP: received 100 CONTINUE");
+ }
+
+ /* we must accept 3 kinds of date, but generate only 1 kind of date */
+ if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
+ apr_table_set(r->headers_out, "Date",
+ ap_proxy_date_canon(p, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
+ apr_table_set(r->headers_out, "Expires",
+ ap_proxy_date_canon(p, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
+ apr_table_set(r->headers_out, "Last-Modified",
+ ap_proxy_date_canon(p, buf));
+ }
+
+ /* munge the Location and URI response headers according to
+ * ProxyPassReverse
+ */
+ if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
+ apr_table_set(r->headers_out, "Location",
+ ap_proxy_location_reverse_map(r, conf, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
+ apr_table_set(r->headers_out, "Content-Location",
+ ap_proxy_location_reverse_map(r, conf, buf));
+ }
+ if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
+ apr_table_set(r->headers_out, "URI",
+ ap_proxy_location_reverse_map(r, conf, buf));
+ }
+
+ if ((r->status == 401) && (conf->error_override != 0)) {
+ const char *wa = "WWW-Authenticate";
+ if ((buf = apr_table_get(r->headers_out, wa))) {
+ apr_table_set(r->err_headers_out, wa, buf);
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: origin server sent 401 without WWW-Authenticate header");
+ }
+ }
+
+ r->sent_bodyct = 1;
+ /* Is it an HTTP/0.9 response? If so, send the extra data */
+ if (backasswards) {
+ apr_ssize_t cntr = len;
+ e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ }
+
+ /* send body - but only if a body is expected */
+ if ((!r->header_only) && /* not HEAD request */
+ (r->status > 199) && /* not any 1xx response */
+ (r->status != HTTP_NO_CONTENT) && /* not 204 */
+ (r->status != HTTP_RESET_CONTENT) && /* not 205 */
+ (r->status != HTTP_NOT_MODIFIED)) { /* not 304 */
+
+ /* We need to copy the output headers and treat them as input
+ * headers as well. BUT, we need to do this before we remove
+ * TE, so that they are preserved accordingly for
+ * ap_http_filter to know where to end.
+ */
+ rp->headers_in = apr_table_copy(r->pool, r->headers_out);
+
+ apr_table_unset(r->headers_out,"Transfer-Encoding");
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: start body send");
+
+ /*
+ * if we are overriding the errors, we can't put the content
+ * of the page into the brigade
+ */
+ if ( (conf->error_override ==0) || r->status < 400 ) {
+
+ /* read the body, pass it to the output filters */
+ int finish = FALSE;
+ while (ap_get_brigade(rp->input_filters,
+ bb,
+ AP_MODE_READBYTES,
+ APR_BLOCK_READ,
+ conf->io_buffer_size) == APR_SUCCESS) {
+#if DEBUGGING
+ {
+ apr_off_t readbytes;
+ apr_brigade_length(bb, 0, &readbytes);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ r->server, "proxy (PID %d): readbytes: %#x",
+ getpid(), readbytes);
+ }
+#endif
+ /* sanity check */
+ if (APR_BRIGADE_EMPTY(bb)) {
+ apr_brigade_cleanup(bb);
+ break;
+ }
+
+ /* found the last brigade? */
+ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+ /* if this is the last brigade, cleanup the
+ * backend connection first to prevent the
+ * backend server from hanging around waiting
+ * for a slow client to eat these bytes
+ */
+ ap_proxy_http_cleanup(r, p_conn, backend);
+ /* signal that we must leave */
+ finish = TRUE;
+ }
+
+ /* try send what we read */
+ if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS
+ || c->aborted) {
+ /* Ack! Phbtt! Die! User aborted! */
+ p_conn->close = 1; /* this causes socket close below */
+ finish = TRUE;
+ }
+
+ /* make sure we always clean up after ourselves */
+ apr_brigade_cleanup(bb);
+
+ /* if we are done, leave */
+ if (TRUE == finish) {
+ break;
+ }
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: end body send");
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: header only");
+ }
+ }
+
+ /* See define of AP_MAX_INTERIM_RESPONSES for why */
+ if (received_continue > AP_MAX_INTERIM_RESPONSES) {
+ return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+ apr_psprintf(p,
+ "Too many (%d) interim responses from origin server",
+ received_continue));
+ }
+
+ if ( conf->error_override ) {
+ /* the code above this checks for 'OK' which is what the hook expects */
+ if ( r->status == HTTP_OK )
+ return OK;
+ else {
+ /* clear r->status for override error, otherwise ErrorDocument
+ * thinks that this is a recursive error, and doesn't find the
+ * custom error page
+ */
+ int status = r->status;
+ r->status = HTTP_OK;
+ /* Discard body, if one is expected */
+ if ((status > 199) && /* not any 1xx response */
+ (status != HTTP_NO_CONTENT) && /* not 204 */
+ (status != HTTP_RESET_CONTENT) && /* not 205 */
+ (status != HTTP_NOT_MODIFIED)) { /* not 304 */
+ ap_discard_request_body(rp);
+ }
+ return status;
+ }
+ } else
+ return OK;
+}
+
+static
+apr_status_t ap_proxy_http_cleanup(request_rec *r, proxy_http_conn_t *p_conn,
+ proxy_conn_rec *backend) {
+ /* If there are no KeepAlives, or if the connection has been signalled
+ * to close, close the socket and clean up
+ */
+
+ /* if the connection is < HTTP/1.1, or Connection: close,
+ * we close the socket, otherwise we leave it open for KeepAlive support
+ */
+ if (p_conn->close || (r->proto_num < HTTP_VERSION(1,1))) {
+ if (p_conn->sock) {
+ apr_socket_close(p_conn->sock);
+ p_conn->sock = NULL;
+ backend->connection = NULL;
+ }
+ }
+ return OK;
+}
+
+/*
+ * This handles http:// URLs, and other URLs using a remote proxy over http
+ * If proxyhost is NULL, then contact the server directly, otherwise
+ * go via the proxy.
+ * Note that if a proxy is used, then URLs other than http: can be accessed,
+ * also, if we have trouble which is clearly specific to the proxy, then
+ * we return DECLINED so that we can try another proxy. (Or the direct
+ * route.)
+ */
+int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
+ char *url, const char *proxyname,
+ apr_port_t proxyport)
+{
+ int status;
+ char server_portstr[32];
+ conn_rec *origin = NULL;
+ proxy_conn_rec *backend = NULL;
+ int is_ssl = 0;
+
+ /* Note: Memory pool allocation.
+ * A downstream keepalive connection is always connected to the existence
+ * (or not) of an upstream keepalive connection. If this is not done then
+ * load balancing against multiple backend servers breaks (one backend
+ * server ends up taking 100% of the load), and the risk is run of
+ * downstream keepalive connections being kept open unnecessarily. This
+ * keeps webservers busy and ties up resources.
+ *
+ * As a result, we allocate all sockets out of the upstream connection
+ * pool, and when we want to reuse a socket, we check first whether the
+ * connection ID of the current upstream connection is the same as that
+ * of the connection when the socket was opened.
+ */
+ apr_pool_t *p = r->connection->pool;
+ conn_rec *c = r->connection;
+ apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
+ apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
+ proxy_http_conn_t *p_conn = apr_pcalloc(r->connection->pool,
+ sizeof(*p_conn));
+
+ /* is it for us? */
+ if (strncasecmp(url, "https:", 6) == 0) {
+ if (!ap_proxy_ssl_enable(NULL)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTPS: declining URL %s"
+ " (mod_ssl not configured?)", url);
+ return DECLINED;
+ }
+ is_ssl = 1;
+ }
+ else if (!(strncasecmp(url, "http:", 5)==0 || (strncasecmp(url, "ftp:", 4)==0 && proxyname))) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTP: declining URL %s", url);
+ return DECLINED; /* only interested in HTTP, or FTP via proxy */
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: HTTP: serving URL %s", url);
+
+
+ /* only use stored info for top-level pages. Sub requests don't share
+ * in keepalives
+ */
+ if (!r->main) {
+ backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
+ &proxy_http_module);
+ }
+ /* create space for state information */
+ if (!backend) {
+ backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec));
+ backend->connection = NULL;
+ backend->hostname = NULL;
+ backend->port = 0;
+ if (!r->main) {
+ ap_set_module_config(c->conn_config, &proxy_http_module, backend);
+ }
+ }
+
+ backend->is_ssl = is_ssl;
+
+ /* Step One: Determine Who To Connect To */
+ status = ap_proxy_http_determine_connection(p, r, p_conn, c, conf, uri,
+ &url, proxyname, proxyport,
+ server_portstr,
+ sizeof(server_portstr));
+ if ( status != OK ) {
+ return status;
+ }
+
+ /* Step Two: Make the Connection */
+ status = ap_proxy_http_create_connection(p, r, p_conn, c, &origin, backend,
+ conf, proxyname);
+ if ( status != OK ) {
+ return status;
+ }
+
+ /* Step Three: Send the Request */
+ status = ap_proxy_http_request(p, r, p_conn, origin, conf, uri, url, bb,
+ server_portstr);
+ if ( status != OK ) {
+ return status;
+ }
+
+ /* Step Four: Receive the Response */
+ status = ap_proxy_http_process_response(p, r, p_conn, origin, backend, conf,
+ bb, server_portstr);
+ if ( status != OK ) {
+ /* clean up even if there is an error */
+ ap_proxy_http_cleanup(r, p_conn, backend);
+ return status;
+ }
+
+ /* Step Five: Clean Up */
+ status = ap_proxy_http_cleanup(r, p_conn, backend);
+ if ( status != OK ) {
+ return status;
+ }
+
+ return OK;
+}
+
+static void ap_proxy_http_register_hook(apr_pool_t *p)
+{
+ proxy_hook_scheme_handler(ap_proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
+ proxy_hook_canon_handler(ap_proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_http_module = {
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-directory config structure */
+ NULL, /* merge per-directory config structures */
+ NULL, /* create per-server config structure */
+ NULL, /* merge per-server config structures */
+ NULL, /* command apr_table_t */
+ ap_proxy_http_register_hook/* register hooks */
+};
+
diff --git a/rubbos/app/httpd-2.0.64/modules/proxy/proxy_util.c b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_util.c
new file mode 100644
index 00000000..bab945f5
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/modules/proxy/proxy_util.c
@@ -0,0 +1,1120 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Utility routines for Apache proxy */
+#include "mod_proxy.h"
+
+
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
+
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
+ (request_rec *r, request_rec *pr), (r, pr),
+ OK, DECLINED)
+
+/* already called in the knowledge that the characters are hex digits */
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x)
+{
+ int i, ch;
+
+#if !APR_CHARSET_EBCDIC
+ ch = x[0];
+ if (apr_isdigit(ch))
+ i = ch - '0';
+ else if (apr_isupper(ch))
+ i = ch - ('A' - 10);
+ else
+ i = ch - ('a' - 10);
+ i <<= 4;
+
+ ch = x[1];
+ if (apr_isdigit(ch))
+ i += ch - '0';
+ else if (apr_isupper(ch))
+ i += ch - ('A' - 10);
+ else
+ i += ch - ('a' - 10);
+ return i;
+#else /*APR_CHARSET_EBCDIC*/
+ /* we assume that the hex value refers to an ASCII character
+ * so convert to EBCDIC so that it makes sense locally;
+ *
+ * example:
+ *
+ * client specifies %20 in URL to refer to a space char;
+ * at this point we're called with EBCDIC "20"; after turning
+ * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
+ * represents an ASCII char and convert 0x20 to EBCDIC, yielding
+ * 0x40
+ */
+ char buf[1];
+
+ if (1 == sscanf(x, "%2x", &i)) {
+ buf[0] = i & 0xFF;
+ ap_xlate_proto_from_ascii(buf, 1);
+ return buf[0];
+ }
+ else {
+ return 0;
+ }
+#endif /*APR_CHARSET_EBCDIC*/
+}
+
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
+{
+#if !APR_CHARSET_EBCDIC
+ int i;
+
+ x[0] = '%';
+ i = (ch & 0xF0) >> 4;
+ if (i >= 10)
+ x[1] = ('A' - 10) + i;
+ else
+ x[1] = '0' + i;
+
+ i = ch & 0x0F;
+ if (i >= 10)
+ x[2] = ('A' - 10) + i;
+ else
+ x[2] = '0' + i;
+#else /*APR_CHARSET_EBCDIC*/
+ static const char ntoa[] = { "0123456789ABCDEF" };
+ char buf[1];
+
+ ch &= 0xFF;
+
+ buf[0] = ch;
+ ap_xlate_proto_to_ascii(buf, 1);
+
+ x[0] = '%';
+ x[1] = ntoa[(buf[0] >> 4) & 0x0F];
+ x[2] = ntoa[buf[0] & 0x0F];
+ x[3] = '\0';
+#endif /*APR_CHARSET_EBCDIC*/
+}
+
+/*
+ * canonicalise a URL-encoded string
+ */
+
+/*
+ * Convert a URL-encoded string to canonical form.
+ * It decodes characters which need not be encoded,
+ * and encodes those which must be encoded, and does not touch
+ * those which must not be touched.
+ */
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
+ int isenc)
+{
+ int i, j, ch;
+ char *y;
+ char *allowed; /* characters which should not be encoded */
+ char *reserved; /* characters which much not be en/de-coded */
+
+/* N.B. in addition to :@&=, this allows ';' in an http path
+ * and '?' in an ftp path -- this may be revised
+ *
+ * Also, it makes a '+' character in a search string reserved, as
+ * it may be form-encoded. (Although RFC 1738 doesn't allow this -
+ * it only permits ; / ? : @ = & as reserved chars.)
+ */
+ if (t == enc_path)
+ allowed = "$-_.+!*'(),;:@&=";
+ else if (t == enc_search)
+ allowed = "$-_.!*'(),;:@&=";
+ else if (t == enc_user)
+ allowed = "$-_.+!*'(),;@&=";
+ else if (t == enc_fpath)
+ allowed = "$-_.+!*'(),?:@&=";
+ else /* if (t == enc_parm) */
+ allowed = "$-_.+!*'(),?/:@&=";
+
+ if (t == enc_path)
+ reserved = "/";
+ else if (t == enc_search)
+ reserved = "+";
+ else
+ reserved = "";
+
+ y = apr_palloc(p, 3 * len + 1);
+
+ for (i = 0, j = 0; i < len; i++, j++) {
+/* always handle '/' first */
+ ch = x[i];
+ if (strchr(reserved, ch)) {
+ y[j] = ch;
+ continue;
+ }
+/* decode it if not already done */
+ if (isenc && (isenc != PROXYREQ_REVERSE) && (ch == '%')) {
+ if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))
+ return NULL;
+ ch = ap_proxy_hex2c(&x[i + 1]);
+ i += 2;
+ if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
+ ap_proxy_c2hex(ch, &y[j]);
+ j += 2;
+ continue;
+ }
+ }
+/* recode it, if necessary */
+ if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
+ ap_proxy_c2hex(ch, &y[j]);
+ j += 2;
+ }
+ else
+ y[j] = ch;
+ }
+ y[j] = '\0';
+ return y;
+}
+
+/*
+ * Parses network-location.
+ * urlp on input the URL; on output the path, after the leading /
+ * user NULL if no user/password permitted
+ * password holder for password
+ * host holder for host
+ * port port number; only set if one is supplied.
+ *
+ * Returns an error string.
+ */
+PROXY_DECLARE(char *)
+ ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
+ char **passwordp, char **hostp, apr_port_t *port)
+{
+ char *addr, *scope_id, *strp, *host, *url = *urlp;
+ char *user = NULL, *password = NULL;
+ apr_port_t tmp_port;
+ apr_status_t rv;
+
+ if (url[0] != '/' || url[1] != '/')
+ return "Malformed URL";
+ host = url + 2;
+ url = strchr(host, '/');
+ if (url == NULL)
+ url = "";
+ else
+ *(url++) = '\0'; /* skip seperating '/' */
+
+ /* find _last_ '@' since it might occur in user/password part */
+ strp = strrchr(host, '@');
+
+ if (strp != NULL) {
+ *strp = '\0';
+ user = host;
+ host = strp + 1;
+
+/* find password */
+ strp = strchr(user, ':');
+ if (strp != NULL) {
+ *strp = '\0';
+ password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
+ if (password == NULL)
+ return "Bad %-escape in URL (password)";
+ }
+
+ user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
+ if (user == NULL)
+ return "Bad %-escape in URL (username)";
+ }
+ if (userp != NULL) {
+ *userp = user;
+ }
+ if (passwordp != NULL) {
+ *passwordp = password;
+ }
+
+ /* Parse the host string to separate host portion from optional port.
+ * Perform range checking on port.
+ */
+ rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
+ if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
+ return "Invalid host/port";
+ }
+ if (tmp_port != 0) { /* only update caller's port if port was specified */
+ *port = tmp_port;
+ }
+
+ ap_str_tolower(addr); /* DNS names are case-insensitive */
+
+ *urlp = url;
+ *hostp = addr;
+
+ return NULL;
+}
+
+/*
+ * If the date is a valid RFC 850 date or asctime() date, then it
+ * is converted to the RFC 1123 format.
+ */
+PROXY_DECLARE(const char *)
+ ap_proxy_date_canon(apr_pool_t *p, const char *date)
+{
+ apr_status_t rv;
+ char* ndate;
+
+ apr_time_t time = apr_date_parse_http(date);
+ if (!time) {
+ return date;
+ }
+
+ ndate = apr_palloc(p, APR_RFC822_DATE_LEN);
+ rv = apr_rfc822_date(ndate, time);
+ if (rv != APR_SUCCESS) {
+ return date;
+ }
+
+ return ndate;
+}
+
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
+{
+ request_rec *rp = apr_pcalloc(c->pool, sizeof(*r));
+
+ rp->pool = c->pool;
+ rp->status = HTTP_OK;
+
+ rp->headers_in = apr_table_make(c->pool, 50);
+ rp->subprocess_env = apr_table_make(c->pool, 50);
+ rp->headers_out = apr_table_make(c->pool, 12);
+ rp->err_headers_out = apr_table_make(c->pool, 5);
+ rp->notes = apr_table_make(c->pool, 5);
+
+ rp->server = r->server;
+ rp->proxyreq = r->proxyreq;
+ rp->request_time = r->request_time;
+ rp->connection = c;
+ rp->output_filters = c->output_filters;
+ rp->input_filters = c->input_filters;
+ rp->proto_output_filters = c->output_filters;
+ rp->proto_input_filters = c->input_filters;
+
+ rp->request_config = ap_create_request_config(c->pool);
+ proxy_run_create_req(r, rp);
+
+ return rp;
+}
+
+/*
+ * Reads headers from a buffer and returns an array of headers.
+ * Returns NULL on file error
+ * This routine tries to deal with too long lines and continuation lines.
+ *
+ * Note: Currently the headers are passed through unmerged. This has to be
+ * done so that headers which react badly to merging (such as Set-Cookie
+ * headers, which contain commas within the date field) do not get stuffed
+ * up.
+ */
+PROXY_DECLARE(apr_table_t *)ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c)
+{
+ apr_table_t *headers_out;
+ int len;
+ char *value, *end;
+ char field[MAX_STRING_LEN];
+ int saw_headers = 0;
+ void *sconf = r->server->module_config;
+ proxy_server_conf *psc;
+
+ psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+
+ headers_out = apr_table_make(r->pool, 20);
+
+ /*
+ * Read header lines until we get the empty separator line, a read error,
+ * the connection closes (EOF), or we timeout.
+ */
+ while ((len = ap_getline(buffer, size, rr, 1)) > 0) {
+
+ if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */
+
+ /* We may encounter invalid headers, usually from buggy
+ * MS IIS servers, so we need to determine just how to handle
+ * them. We can either ignore them, assume that they mark the
+ * start-of-body (eg: a missing CRLF) or (the default) mark
+ * the headers as totally bogus and return a 500. The sole
+ * exception is an extra "HTTP/1.0 200, OK" line sprinkled
+ * in between the usual MIME headers, which is a favorite
+ * IIS bug.
+ */
+ /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
+
+ if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+ if (psc->badopt == bad_error) {
+ /* Nope, it wasn't even an extra HTTP header. Give up. */
+ return NULL;
+ }
+ else if (psc->badopt == bad_body) {
+ /* if we've already started loading headers_out, then
+ * return what we've accumulated so far, in the hopes
+ * that they are useful. Otherwise, we completely bail.
+ */
+ /* FIXME: We've already scarfed the supposed 1st line of
+ * the body, so the actual content may end up being bogus
+ * as well. If the content is HTML, we may be lucky.
+ */
+ if (saw_headers) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: Starting body due to bogus non-header in headers "
+ "returned by %s (%s)", r->uri, r->method);
+ return headers_out;
+ } else {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: No HTTP headers "
+ "returned by %s (%s)", r->uri, r->method);
+ return NULL;
+ }
+ }
+ }
+ /* this is the psc->badopt == bad_ignore case */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: Ignoring bogus HTTP header "
+ "returned by %s (%s)", r->uri, r->method);
+ continue;
+ }
+
+ *value = '\0';
+ ++value;
+ /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
+ * wrong... and so are many others probably.
+ */
+ while (apr_isspace(*value))
+ ++value; /* Skip to start of value */
+
+ /* should strip trailing whitespace as well */
+ for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end)
+ *end = '\0';
+
+ /* make sure we add so as not to destroy duplicated headers */
+ apr_table_add(headers_out, buffer, value);
+ saw_headers = 1;
+
+ /* the header was too long; at the least we should skip extra data */
+ if (len >= size - 1) {
+ while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))
+ >= MAX_STRING_LEN - 1) {
+ /* soak up the extra data */
+ }
+ if (len == 0) /* time to exit the larger loop as well */
+ break;
+ }
+ }
+ return headers_out;
+}
+
+
+/*
+ * list is a comma-separated list of case-insensitive tokens, with
+ * optional whitespace around the tokens.
+ * The return returns 1 if the token val is found in the list, or 0
+ * otherwise.
+ */
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
+{
+ int len, i;
+ const char *p;
+
+ len = strlen(val);
+
+ while (list != NULL) {
+ p = ap_strchr_c(list, ',');
+ if (p != NULL) {
+ i = p - list;
+ do
+ p++;
+ while (apr_isspace(*p));
+ }
+ else
+ i = strlen(list);
+
+ while (i > 0 && apr_isspace(list[i - 1]))
+ i--;
+ if (i == len && strncasecmp(list, val, len) == 0)
+ return 1;
+ list = p;
+ }
+ return 0;
+}
+
+/*
+ * list is a comma-separated list of case-insensitive tokens, with
+ * optional whitespace around the tokens.
+ * if val appears on the list of tokens, it is removed from the list,
+ * and the new list is returned.
+ */
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
+{
+ int len, i;
+ const char *p;
+ char *new = NULL;
+
+ len = strlen(val);
+
+ while (list != NULL) {
+ p = ap_strchr_c(list, ',');
+ if (p != NULL) {
+ i = p - list;
+ do
+ p++;
+ while (apr_isspace(*p));
+ }
+ else
+ i = strlen(list);
+
+ while (i > 0 && apr_isspace(list[i - 1]))
+ i--;
+ if (i == len && strncasecmp(list, val, len) == 0) {
+ /* do nothing */
+ }
+ else {
+ if (new)
+ new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
+ else
+ new = apr_pstrndup(pool, list, i);
+ }
+ list = p;
+ }
+ return new;
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x)
+{
+ int i, ch;
+ unsigned int j;
+
+ for (i = 0, j = 0; i < 8; i++) {
+ ch = x[i];
+ j <<= 4;
+ if (apr_isdigit(ch))
+ j |= ch - '0';
+ else if (apr_isupper(ch))
+ j |= ch - ('A' - 10);
+ else
+ j |= ch - ('a' - 10);
+ }
+ if (j == 0xffffffff)
+ return -1; /* so that it works with 8-byte ints */
+ else
+ return j;
+}
+
+/*
+ * Converts a time integer to 8 hex digits
+ */
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y)
+{
+ int i, ch;
+ unsigned int j = t;
+
+ for (i = 7; i >= 0; i--) {
+ ch = j & 0xF;
+ j >>= 4;
+ if (ch >= 10)
+ y[i] = ch + ('A' - 10);
+ else
+ y[i] = ch + '0';
+ }
+ y[8] = '\0';
+}
+
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
+{
+ apr_table_setn(r->notes, "error-notes",
+ apr_pstrcat(r->pool,
+ "The proxy server could not handle the request "
+ "<em><a href=\"", ap_escape_uri(r->pool, r->uri),
+ "\">", ap_escape_html(r->pool, r->method),
+ "&nbsp;",
+ ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
+ "Reason: <strong>",
+ ap_escape_html(r->pool, message),
+ "</strong></p>", NULL));
+
+ /* Allow "error-notes" string to be printed by ap_send_error_response() */
+ apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
+
+ r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: %s returned by %s", message, r->uri);
+ return statuscode;
+}
+
+static const char *
+ proxy_get_host_of_request(request_rec *r)
+{
+ char *url, *user = NULL, *password = NULL, *err, *host;
+ apr_port_t port;
+
+ if (r->hostname != NULL)
+ return r->hostname;
+
+ /* Set url to the first char after "scheme://" */
+ if ((url = strchr(r->uri, ':')) == NULL
+ || url[1] != '/' || url[2] != '/')
+ return NULL;
+
+ url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
+
+ err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
+
+ if (err != NULL)
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "%s", err);
+
+ r->hostname = host;
+
+ return host; /* ought to return the port, too */
+}
+
+/* Return TRUE if addr represents an IP address (or an IP network address) */
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
+{
+ const char *addr = This->name;
+ long ip_addr[4];
+ int i, quads;
+ long bits;
+
+ /* if the address is given with an explicit netmask, use that */
+ /* Due to a deficiency in apr_inet_addr(), it is impossible to parse */
+ /* "partial" addresses (with less than 4 quads) correctly, i.e. */
+ /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
+ /* I therefore have to parse the IP address manually: */
+ /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */
+ /* addr and mask were set by proxy_readmask() */
+ /*return 1; */
+
+ /* Parse IP addr manually, optionally allowing */
+ /* abbreviated net addresses like 192.168. */
+
+ /* Iterate over up to 4 (dotted) quads. */
+ for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
+ char *tmp;
+
+ if (*addr == '/' && quads > 0) /* netmask starts here. */
+ break;
+
+ if (!apr_isdigit(*addr))
+ return 0; /* no digit at start of quad */
+
+ ip_addr[quads] = strtol(addr, &tmp, 0);
+
+ if (tmp == addr) /* expected a digit, found something else */
+ return 0;
+
+ if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
+ /* invalid octet */
+ return 0;
+ }
+
+ addr = tmp;
+
+ if (*addr == '.' && quads != 3)
+ ++addr; /* after the 4th quad, a dot would be illegal */
+ }
+
+ for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
+ This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+
+ if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */
+ char *tmp;
+
+ ++addr;
+
+ bits = strtol(addr, &tmp, 0);
+
+ if (tmp == addr) /* expected a digit, found something else */
+ return 0;
+
+ addr = tmp;
+
+ if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
+ return 0;
+
+ }
+ else {
+ /* Determine (i.e., "guess") netmask by counting the */
+ /* number of trailing .0's; reduce #quads appropriately */
+ /* (so that 192.168.0.0 is equivalent to 192.168.) */
+ while (quads > 0 && ip_addr[quads - 1] == 0)
+ --quads;
+
+ /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
+ if (quads < 1)
+ return 0;
+
+ /* every zero-byte counts as 8 zero-bits */
+ bits = 8 * quads;
+
+ if (bits != 32) /* no warning for fully qualified IP address */
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
+ inet_ntoa(This->addr), bits);
+ }
+
+ This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
+
+ if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "Warning: NetMask and IP-Addr disagree in %s/%ld",
+ inet_ntoa(This->addr), bits);
+ This->addr.s_addr &= This->mask.s_addr;
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ " Set to %s/%ld",
+ inet_ntoa(This->addr), bits);
+ }
+
+ if (*addr == '\0') {
+ This->matcher = proxy_match_ipaddr;
+ return 1;
+ }
+ else
+ return (*addr == '\0'); /* okay iff we've parsed the whole string */
+}
+
+/* Return TRUE if addr represents an IP address (or an IP network address) */
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
+{
+ int i, ip_addr[4];
+ struct in_addr addr, *ip;
+ const char *host = proxy_get_host_of_request(r);
+
+ if (host == NULL) /* oops! */
+ return 0;
+
+ memset(&addr, '\0', sizeof addr);
+ memset(ip_addr, '\0', sizeof ip_addr);
+
+ if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
+ for (addr.s_addr = 0, i = 0; i < 4; ++i)
+ addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+
+ if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s/", inet_ntoa(This->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s", inet_ntoa(This->mask));
+#endif
+ return 1;
+ }
+#if DEBUGGING
+ else {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s/", inet_ntoa(This->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s", inet_ntoa(This->mask));
+ }
+#endif
+ }
+ else {
+ struct apr_sockaddr_t *reqaddr;
+
+ if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
+ != APR_SUCCESS) {
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "2)IP-NoMatch: hostname=%s msg=Host not found",
+ host);
+#endif
+ return 0;
+ }
+
+ /* Try to deal with multiple IP addr's for a host */
+ /* FIXME: This needs to be able to deal with IPv6 */
+ while (reqaddr) {
+ ip = (struct in_addr *) reqaddr->ipaddr_ptr;
+ if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
+#if DEBUGGING
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "3)IP-Match: %s[%s] <-> ", host,
+ inet_ntoa(*ip));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s/", inet_ntoa(This->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s", inet_ntoa(This->mask));
+#endif
+ return 1;
+ }
+#if DEBUGGING
+ else {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "3)IP-NoMatch: %s[%s] <-> ", host,
+ inet_ntoa(*ip));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s/", inet_ntoa(This->addr));
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "%s", inet_ntoa(This->mask));
+ }
+#endif
+ reqaddr = reqaddr->next;
+ }
+ }
+
+ return 0;
+}
+
+/* Return TRUE if addr represents a domain name */
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
+{
+ char *addr = This->name;
+ int i;
+
+ /* Domain name must start with a '.' */
+ if (addr[0] != '.')
+ return 0;
+
+ /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
+ for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
+ continue;
+
+#if 0
+ if (addr[i] == ':') {
+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+ "@@@@ handle optional port in proxy_is_domainname()");
+ /* @@@@ handle optional port */
+ }
+#endif
+
+ if (addr[i] != '\0')
+ return 0;
+
+ /* Strip trailing dots */
+ for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
+ addr[i] = '\0';
+
+ This->matcher = proxy_match_domainname;
+ return 1;
+}
+
+/* Return TRUE if host "host" is in domain "domain" */
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
+{
+ const char *host = proxy_get_host_of_request(r);
+ int d_len = strlen(This->name), h_len;
+
+ if (host == NULL) /* some error was logged already */
+ return 0;
+
+ h_len = strlen(host);
+
+ /* @@@ do this within the setup? */
+ /* Ignore trailing dots in domain comparison: */
+ while (d_len > 0 && This->name[d_len - 1] == '.')
+ --d_len;
+ while (h_len > 0 && host[h_len - 1] == '.')
+ --h_len;
+ return h_len > d_len
+ && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
+}
+
+/* Return TRUE if host represents a host name */
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
+{
+ struct apr_sockaddr_t *addr;
+ char *host = This->name;
+ int i;
+
+ /* Host names must not start with a '.' */
+ if (host[0] == '.')
+ return 0;
+
+ /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
+ for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
+
+ if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS)
+ return 0;
+
+ This->hostaddr = addr;
+
+ /* Strip trailing dots */
+ for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i)
+ host[i] = '\0';
+
+ This->matcher = proxy_match_hostname;
+ return 1;
+}
+
+/* Return TRUE if host "host" is equal to host2 "host2" */
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
+{
+ char *host = This->name;
+ const char *host2 = proxy_get_host_of_request(r);
+ int h2_len;
+ int h1_len;
+
+ if (host == NULL || host2 == NULL)
+ return 0; /* oops! */
+
+ h2_len = strlen(host2);
+ h1_len = strlen(host);
+
+#if 0
+ struct apr_sockaddr_t *addr = *This->hostaddr;
+
+ /* Try to deal with multiple IP addr's for a host */
+ while (addr) {
+ if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
+ return 1;
+ addr = addr->next;
+ }
+#endif
+
+ /* Ignore trailing dots in host2 comparison: */
+ while (h2_len > 0 && host2[h2_len - 1] == '.')
+ --h2_len;
+ while (h1_len > 0 && host[h1_len - 1] == '.')
+ --h1_len;
+ return h1_len == h2_len
+ && strncasecmp(host, host2, h1_len) == 0;
+}
+
+/* Return TRUE if addr is to be matched as a word */
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
+{
+ This->matcher = proxy_match_word;
+ return 1;
+}
+
+/* Return TRUE if string "str2" occurs literally in "str1" */
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
+{
+ const char *host = proxy_get_host_of_request(r);
+ return host != NULL && ap_strstr_c(host, This->name) != NULL;
+}
+
+/* checks whether a host in uri_addr matches proxyblock */
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf,
+ apr_sockaddr_t *uri_addr)
+{
+ int j;
+ apr_sockaddr_t * src_uri_addr = uri_addr;
+ /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
+ for (j = 0; j < conf->noproxies->nelts; j++) {
+ struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
+ struct apr_sockaddr_t *conf_addr = npent[j].addr;
+ uri_addr = src_uri_addr;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
+ if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
+ || npent[j].name[0] == '*') {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
+ return HTTP_FORBIDDEN;
+ }
+ while (conf_addr) {
+ while (uri_addr) {
+ char *conf_ip;
+ char *uri_ip;
+ apr_sockaddr_ip_get(&conf_ip, conf_addr);
+ apr_sockaddr_ip_get(&uri_ip, uri_addr);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
+ if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+ "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
+ return HTTP_FORBIDDEN;
+ }
+ uri_addr = uri_addr->next;
+ }
+ conf_addr = conf_addr->next;
+ }
+ }
+ return OK;
+}
+
+/* set up the minimal filter set */
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
+{
+ ap_add_input_filter("HTTP_IN", NULL, r, c);
+ return OK;
+}
+
+/* converts a series of buckets into a string
+ * XXX: BillS says this function performs essentially the same function as
+ * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline()
+ * instead? I think ap_proxy_string_read() will not work properly on non ASCII
+ * (EBCDIC) machines either.
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
+ char *buff, apr_size_t bufflen, int *eos)
+{
+ apr_bucket *e;
+ apr_status_t rv;
+ char *pos = buff;
+ char *response;
+ int found = 0;
+ apr_size_t len;
+
+ /* start with an empty string */
+ buff[0] = 0;
+ *eos = 0;
+
+ /* loop through each brigade */
+ while (!found) {
+ /* get brigade from network one line at a time */
+ if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb,
+ AP_MODE_GETLINE,
+ APR_BLOCK_READ,
+ 0))) {
+ return rv;
+ }
+ /* loop through each bucket */
+ while (!found) {
+ if (*eos || APR_BRIGADE_EMPTY(bb)) {
+ /* The connection aborted or timed out */
+ return APR_ECONNABORTED;
+ }
+ e = APR_BRIGADE_FIRST(bb);
+ if (APR_BUCKET_IS_EOS(e)) {
+ *eos = 1;
+ }
+ else {
+ if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {
+ return rv;
+ }
+ /* is string LF terminated?
+ * XXX: This check can be made more efficient by simply checking
+ * if the last character in the 'response' buffer is an ASCII_LF.
+ * See ap_rgetline() for an example.
+ */
+ if (memchr(response, APR_ASCII_LF, len)) {
+ found = 1;
+ }
+ /* concat strings until buff is full - then throw the data away */
+ if (len > ((bufflen-1)-(pos-buff))) {
+ len = (bufflen-1)-(pos-buff);
+ }
+ if (len > 0) {
+ pos = apr_cpystrn(pos, response, len);
+ }
+ }
+ APR_BUCKET_REMOVE(e);
+ apr_bucket_destroy(e);
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+/* unmerge an element in the table */
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)
+{
+ apr_off_t offset = 0;
+ apr_off_t count = 0;
+ char *value = NULL;
+
+ /* get the value to unmerge */
+ const char *initial = apr_table_get(t, key);
+ if (!initial) {
+ return;
+ }
+ value = apr_pstrdup(p, initial);
+
+ /* remove the value from the headers */
+ apr_table_unset(t, key);
+
+ /* find each comma */
+ while (value[count]) {
+ if (value[count] == ',') {
+ value[count] = 0;
+ apr_table_add(t, key, value + offset);
+ offset = count + 1;
+ }
+ count++;
+ }
+ apr_table_add(t, key, value + offset);
+}
+
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
+ const char *proxy_function,
+ apr_sockaddr_t *backend_addr,
+ const char *backend_name,
+ proxy_server_conf *conf,
+ server_rec *s,
+ apr_pool_t *p)
+{
+ apr_status_t rv;
+ int connected = 0;
+ int loglevel;
+
+ while (backend_addr && !connected) {
+ if ((rv = apr_socket_create(newsock, backend_addr->family,
+ SOCK_STREAM, p)) != APR_SUCCESS) {
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s,
+ "proxy: %s: error creating fam %d socket for target %s",
+ proxy_function,
+ backend_addr->family,
+ backend_name);
+ /* this could be an IPv6 address from the DNS but the
+ * local machine won't give us an IPv6 socket; hopefully the
+ * DNS returned an additional address to try
+ */
+ backend_addr = backend_addr->next;
+ continue;
+ }
+
+#if !defined(TPF) && !defined(BEOS)
+ if (conf->recv_buffer_size > 0 &&
+ (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,
+ conf->recv_buffer_size))) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+ "apr_socket_opt_set(SO_RCVBUF): Failed to set "
+ "ProxyReceiveBufferSize, using default");
+ }
+#endif
+
+ /* Set a timeout on the socket */
+ if (conf->timeout_set == 1) {
+ apr_socket_timeout_set(*newsock, conf->timeout);
+ }
+ else {
+ apr_socket_timeout_set(*newsock, s->timeout);
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "proxy: %s: fam %d socket created to connect to %s",
+ proxy_function, backend_addr->family, backend_name);
+
+ /* make the connection out of the socket */
+ rv = apr_connect(*newsock, backend_addr);
+
+ /* if an error occurred, loop round and try again */
+ if (rv != APR_SUCCESS) {
+ apr_socket_close(*newsock);
+ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+ ap_log_error(APLOG_MARK, loglevel, rv, s,
+ "proxy: %s: attempt to connect to %pI (%s) failed",
+ proxy_function,
+ backend_addr,
+ backend_name);
+ backend_addr = backend_addr->next;
+ continue;
+ }
+ connected = 1;
+ }
+ return connected ? 0 : 1;
+}
+