From 7eb36e66a096d52caf5ca1a0513a59238ff30ecb Mon Sep 17 00:00:00 2001 From: Antonio Pisano Date: Thu, 28 Nov 2024 17:32:16 +0100 Subject: [PATCH 1/3] Allow to forwarded a completely handcrafted request to the backend --- revproxy-ns-connchan-procs.tcl | 13 ++++++------ revproxy-ns-http-procs.tcl | 12 +++++------ revproxy-procs.tcl | 39 +++++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/revproxy-ns-connchan-procs.tcl b/revproxy-ns-connchan-procs.tcl index 2c68574..7d4f610 100644 --- a/revproxy-ns-connchan-procs.tcl +++ b/revproxy-ns-connchan-procs.tcl @@ -26,6 +26,10 @@ namespace eval ::revproxy::ns_connchan { {-exception_callback "::revproxy::exception"} {-url_rewrite_callback "::revproxy::rewrite_url"} {-backend_reply_callback ""} + -method + -content + -contentfile + -queryHeaders } { # # Inject a "connection close" instruction to avoid persistent @@ -37,7 +41,6 @@ namespace eval ::revproxy::ns_connchan { # # We might have to take more precautions for WebSockets here. # - set queryHeaders [ns_conn headers] ns_set iupdate $queryHeaders connection close #ns_log notice queryHeaders=[ns_set array $queryHeaders] @@ -63,7 +66,7 @@ namespace eval ::revproxy::ns_connchan { # set backendChan [ns_connchan open \ {*}$unixSocketArg \ - -method [ns_conn method] \ + -method $method \ -headers $queryHeaders \ -timeout $timeout \ -version [ns_conn version] \ @@ -73,20 +76,18 @@ namespace eval ::revproxy::ns_connchan { # set contentLength [ns_set iget $queryHeaders content-length {}] if {$contentLength ne ""} { - set contentfile [ns_conn contentfile] set chunk 16000 if {$contentfile eq ""} { # # string content # - set data [ns_conn content -binary] - set length [string length $data] + set length $contentLength set i 0 set j [expr {$chunk -1}] while {$i < $length} { log notice "upstream: send max $chunk bytes from string to $backendChan " \ "(length $contentLength)" - ns_connchan write -buffered $backendChan [string range $data $i $j] + ns_connchan write -buffered $backendChan [string range $content $i $j] incr i $chunk incr j $chunk } diff --git a/revproxy-ns-http-procs.tcl b/revproxy-ns-http-procs.tcl index 06d5f93..20f25c3 100644 --- a/revproxy-ns-http-procs.tcl +++ b/revproxy-ns-http-procs.tcl @@ -13,6 +13,10 @@ namespace eval ::revproxy::ns_http { {-validation_callback ""} {-exception_callback "::revproxy::exception"} {-backend_reply_callback ""} + -method + -content + -contentfile + -queryHeaders } { # # Now perform the transmission... but before this, call the @@ -24,11 +28,10 @@ namespace eval ::revproxy::ns_http { {*}$validation_callback -url $url } - set queryHeaders [ns_conn headers] set binary false set extraArgs {} - switch [ns_conn method] { + switch $method { PUT - POST { set contentType [ns_set iget $queryHeaders content-type] @@ -36,13 +39,10 @@ namespace eval ::revproxy::ns_http { && [ns_encodingfortype $contentType] eq "binary"} { set binary true } - set contentfile [ns_conn contentfile] if {$contentfile ne ""} { lappend extraArgs -body_file $contentfile - } elseif {$binary} { - lappend extraArgs -body [ns_conn content -binary] } else { - lappend extraArgs -body [ns_conn content] + lappend extraArgs -body $content } } default {} diff --git a/revproxy-procs.tcl b/revproxy-procs.tcl index ee77e34..301f418 100644 --- a/revproxy-procs.tcl +++ b/revproxy-procs.tcl @@ -32,6 +32,12 @@ namespace eval ::revproxy { # # Serve the requested file from an upstream server, which might be # an HTTP or HTTPS server. + # + # By default, headers method and request body will be those of the + # current request. One can craft a custom request to be forwarded + # to the backend overriding these parameters via the "method", + # "content" / "contentfile" and "queryHeaders" flags. + # nsf::proc upstream { when @@ -45,6 +51,10 @@ namespace eval ::revproxy { {-url_rewrite_callback "::revproxy::rewrite_url"} {-backend_reply_callback ""} {-backendconnection ""} + {-method ""} + {-content ""} + {-contentfile ""} + {-headers ""} } { if {$backendconnection eq ""} { @@ -130,7 +140,9 @@ namespace eval ::revproxy { # Get header fields from request, add x-forwarded-for, # x-forwarded-proto, and x-ssl-request (if appropriate). # - set queryHeaders [ns_conn headers] + if {$queryHeaders eq ""} { + set queryHeaders [ns_conn headers] + } set XForwardedFor [split [ns_set iget $queryHeaders "x-forwarded-for" ""] " ,"] set XForwardedFor [lmap e $XForwardedFor {if {$e eq ""} continue}] @@ -143,6 +155,27 @@ namespace eval ::revproxy { ns_set iupdate $queryHeaders x-ssl-request 1 } + if {$method eq ""} { + set method [ns_conn method] + } + + set contentType [ns_set iget $queryHeaders content-type] + set binary [expr {$contentType ne "" && [ns_encodingfortype $contentType] eq "binary"}] + + if {$content ne ""} { + ns_set iupdate $queryHeaders content-length [string length $content] + } elseif {$binary} { + set content [ns_conn content -binary] + } else { + set content [ns_conn content] + } + + if {$contentfile ne ""} { + ns_set iupdate $queryHeaders content-length [file size $contentfile] + } else { + set contentfile [ns_conn contentfile] + } + # # Finally, start the transmission to the backend via the # configured means. @@ -155,6 +188,10 @@ namespace eval ::revproxy { -validation_callback $validation_callback \ -exception_callback $exception_callback \ -backend_reply_callback $backend_reply_callback \ + -method $method \ + -content $content \ + -contentfile $contentfile \ + -queryHeaders $queryHeaders \ ] } From 1a52ba78d5d29910e56741231811f5e76c0f4e84 Mon Sep 17 00:00:00 2001 From: Antonio Pisano Date: Thu, 28 Nov 2024 17:36:07 +0100 Subject: [PATCH 2/3] The method is already passed to the api --- revproxy-procs.tcl | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/revproxy-procs.tcl b/revproxy-procs.tcl index 301f418..e8f496a 100644 --- a/revproxy-procs.tcl +++ b/revproxy-procs.tcl @@ -35,8 +35,8 @@ namespace eval ::revproxy { # # By default, headers method and request body will be those of the # current request. One can craft a custom request to be forwarded - # to the backend overriding these parameters via the "method", - # "content" / "contentfile" and "queryHeaders" flags. + # to the backend overriding these parameters via the "content" / + # "contentfile" and "queryHeaders" flags. # nsf::proc upstream { @@ -51,7 +51,6 @@ namespace eval ::revproxy { {-url_rewrite_callback "::revproxy::rewrite_url"} {-backend_reply_callback ""} {-backendconnection ""} - {-method ""} {-content ""} {-contentfile ""} {-headers ""} @@ -155,10 +154,6 @@ namespace eval ::revproxy { ns_set iupdate $queryHeaders x-ssl-request 1 } - if {$method eq ""} { - set method [ns_conn method] - } - set contentType [ns_set iget $queryHeaders content-type] set binary [expr {$contentType ne "" && [ns_encodingfortype $contentType] eq "binary"}] @@ -188,7 +183,7 @@ namespace eval ::revproxy { -validation_callback $validation_callback \ -exception_callback $exception_callback \ -backend_reply_callback $backend_reply_callback \ - -method $method \ + -method $when \ -content $content \ -contentfile $contentfile \ -queryHeaders $queryHeaders \ From f5940f3cd50c3bc20d6817003463c6adcaf92fc9 Mon Sep 17 00:00:00 2001 From: Antonio Pisano Date: Thu, 28 Nov 2024 17:37:50 +0100 Subject: [PATCH 3/3] Fixy typo --- revproxy-procs.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/revproxy-procs.tcl b/revproxy-procs.tcl index e8f496a..def902e 100644 --- a/revproxy-procs.tcl +++ b/revproxy-procs.tcl @@ -53,7 +53,7 @@ namespace eval ::revproxy { {-backendconnection ""} {-content ""} {-contentfile ""} - {-headers ""} + {-queryHeaders ""} } { if {$backendconnection eq ""} {