util::http::follow_redirects (private)

 util::http::follow_redirects [ -url url ] [ -method method ] \
    [ -status status ] [ -location location ] [ -body body ] \
    [ -body_file body_file ] [ -delete_body_file ] \
    [ -headers headers ] [ -timeout timeout ] [ -depth depth ] \
    [ -max_depth max_depth ] [ -force_ssl ] [ -multipart ] \
    [ -gzip_request ] [ -gzip_response ] [ -post_redirect ] [ -spool ] \
    [ -preference preference ] [ native ]

Defined in packages/acs-tcl/tcl/http-client-procs.tcl

Follow redirects. This proc is required because we want to be able to follow a redirect until a certain depth and then stop without throwing an error. Happens at times that even a redirect page contains very important information we want to be able to reach. An example could be authentication headers. By putting redirection handling here we can force a common behavior between the two implementations, that otherwise would not be possible.

Switches:
-url (optional)
-method (optional)
-status (optional)
-location (optional)
-body (optional)
is the payload for the request and will be passed as is (useful for many purposes, such as webDav). A convenient way to specify form variables through this argument is passing a string obtained by 'export_vars -url'. Default behavior is to build payload as an 'application/x-www-form-urlencoded' payload if no files are specified, and 'multipart/form-data' otherwise. If '-multipart' flag is set, format will be forced to multipart.
-body_file (optional)
is an alternative way to specify the payload, useful in cases such as the upload of big files by POST. If specified, will have precedence over the 'body' parameter. Content of the file won't be encoded according with the content type of the request as happen with 'body'
-delete_body_file (optional, boolean)
decides whether remove body payload file once the request is over.
-headers (optional)
specifies an ns_set of extra headers to send to the server when doing the request. Some options exist that allow one to avoid the need to specify headers manually, but headers will always take precedence over options.
-timeout (optional, defaults to "30")
Timeout in seconds. The value can be an integer, a floating point number or an ns_time value.
-depth (optional, defaults to "0")
-max_depth (optional, defaults to "10")
is the maximum number of redirects the proc is allowed to follow. A value of 0 disables redirection. When max depth for redirection has been reached, proc will return response from the last page we were redirected to. This is important if redirection response contains data such as cookies we need to obtain anyway. Be aware that when following redirects, unless it is a code 303 redirect, url and POST urlencoded variables will be sent again to the redirected host. Multipart variables won't be sent again. Sending to the redirected host can be dangerous, if such host is not trusted or uses a lower level of security.
-force_ssl (optional, boolean)
specifies whether we want to use SSL despite the url being in http:// form. Default behavior is to use SSL on https:// URLs only.
-multipart (optional, boolean)
-gzip_request (optional, boolean)
informs the server that we are sending data in gzip format. Data will be automatically compressed. Notice that not all servers can treat gzipped requests properly, and in such cases response will likely be an error.
-gzip_response (optional, boolean)
informs the server that we are capable of receiving gzipped responses. If server complies to our indication, the result will be automatically decompressed.
-post_redirect (optional, boolean)
decides what happens when we are POSTing and server replies with 301, 302 or 303 redirects. RFC 2616/10.3.2 states that method should not change when 301 or 302 are returned, and that GET should be used on a 303 response, but most HTTP clients fail in respecting this and switch to a GET request independently. This option forces this kinds of redirect to conserve their original method.
-spool (optional, boolean)
enables file spooling of the request on the file specified. It is useful when we expect large responses from the server. The result is spooled to a temporary file, the name is returned in the file component of the result.
-preference (optional)
decides which available implementation prefer in respective order. Choice is between 'native', based on ns_ api, available for NaviServer only and giving the best performances and 'curl', which wraps the command line utility (available on every system with curl installed).
Parameters:
native (optional, defaults to "curl")
Returns:
the data as dict with elements 'headers', 'page', 'file', 'status', 'time' (elapsed request time in ns_time format), and 'modified' from the last followed redirect, or an empty string if request was not a redirection.

Partial Call Graph (max 5 caller/called nodes):
%3 util::http::curl::request util::http::curl::request (private) util::http::follow_redirects util::http::follow_redirects util::http::curl::request->util::http::follow_redirects util::http::native::request util::http::native::request (private) util::http::native::request->util::http::follow_redirects

Testcases:
No testcase defined.
Source code:
    ## Redirection management ##

    # Don't follow if page was not modified or this was not a proper redirect:
    # not the right status code, missing location.
    if {$status == 304 || ![string match "3??" $status] || $location eq ""} {
        return ""
    }

    # Other kinds of redirection...
    # Decide by which method follow the redirect
    if {$method eq "POST"} {
        if {$status in {301 302 303} && !$post_redirect_p} {
            set method "GET"
        }
    }

    #
    # A redirect from HTTP might point to HTTPS, which in turn
    # might not be configured. So we have to go through
    # util::http::request again.
    #
    set this_proc ::util::http::request

    set urlvars [list]

    # ...retrieve redirect location variables...
    set locvars [lindex [split $location ?] 1]
    if {$locvars ne ""} {
        lappend urlvars $locvars
    }

    lappend urlvars [lindex [split $url ?] 1]

    # If we have POST payload and we are following by GET, put the payload into url vars.
    if {$method eq "GET" && $body ne ""} {
        set req_content_type [ns_set iget $headers "content-type"]
        set multipart_p [string match -nocase "*multipart/form-data*" $req_content_type]
        # I decided to don't translate into urlvars a multipart payload.
        # This makes sense if we think that in a multipart payload we have
        # some information, such as mime_type, which cannot be put into url.
        # Receiving a GET redirect after a POST is very common, so I won't throw an error
        if {!$multipart_p} {
            if {$gzip_request_p} {
                set body [zlib gunzip $body]
            }
            lappend urlvars $body
        }
    }

    # Unite all variables into location URL
    set urlvars [join $urlvars &]

    if {$urlvars ne ""} {
        set location ${location}?${urlvars}
    }

    #
    # According to
    # https://www.rfc-editor.org/rfc/rfc7231#section-7.1.2, the
    # location header may return a relative URL as well.
    #
    set location [ns_absoluteurl $location $url]

    if {$method eq "GET"} {
        return [$this_proc  -method          GET  -url             $location  -headers         $headers  -timeout         $timeout  -depth           $depth  -max_depth       $max_depth  -force_ssl=$force_ssl_p  -gzip_response=$gzip_response_p  -post_redirect=$post_redirect_p  -spool=$spool_p  -preference $preference]
    } else {
        return [$this_proc  -method          POST  -url             $location  -body            $body  -body_file       $body_file  -delete_body_file=$delete_body_file_p  -headers         $headers  -timeout         $timeout  -depth           $depth  -max_depth       $max_depth  -force_ssl=$force_ssl_p  -gzip_request=$gzip_request_p  -gzip_response=$gzip_response_p  -post_redirect=$post_redirect_p  -spool=$spool_p  -preference $preference]
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: