@@ -26,7 +26,9 @@ type Options struct {
2626 Servers []string
2727 DynamicCompileAllowed bool
2828 ReferrerPolicy string
29- ScriptRewriter func (source , kind , targetURL , controlPrefix string ) (string , error )
29+ ScriptRewriter func (source , kind , targetURL , controlPrefix , tabID , runtimeToken string ) (string , error )
30+ ScriptURLRewriter func (raw , kind , targetURL , controlPrefix , tabID , runtimeToken string ) (wrapped , target string , err error )
31+ FetchURLRewriter func (raw , targetURL , controlPrefix string ) (wrapped , target string , err error )
3032 CSSRewriter func (source , baseURL string ) (string , error )
3133 ImportMapRewriter func (source , baseURL , tabID , runtimeToken , controlPrefix string ) (string , error )
3234}
@@ -668,7 +670,11 @@ func rewriteSrcset(raw string, opt Options) (rewritten, visible string, changed
668670 continue
669671 }
670672 out = append (out , joinSrcsetCandidate (wrapped , c .descriptor ))
671- vis = append (vis , joinSrcsetCandidate (target , c .descriptor ))
673+ if target != "" {
674+ vis = append (vis , joinSrcsetCandidate (target , c .descriptor ))
675+ } else {
676+ vis = append (vis , c .raw )
677+ }
672678 changed = true
673679 }
674680 if ! changed {
@@ -842,45 +848,19 @@ func wrapAttrURL(raw string, opt Options, nav bool) (wrapped, target string, ok
842848}
843849
844850func wrapScriptURL (raw string , opt Options , kind string ) (wrapped , target string , ok bool ) {
845- s := strings .TrimSpace (raw )
846- blocked := shareurl .ControlPrefix + "error/POLICY_BLOCKED"
847- if s == "" || strings .HasPrefix (s , "#" ) || hasExecutableURLScheme (s ) {
848- return blocked , "" , false
849- }
850- u , err := url .Parse (s )
851- if err != nil {
852- return blocked , "" , false
853- }
854- abs := opt .TargetURL .ResolveReference (u )
855- if abs .Scheme != "http" && abs .Scheme != "https" {
856- return blocked , "" , false
857- }
858- q := url.Values {}
859- q .Set ("u" , abs .String ())
860- q .Set ("kind" , kind )
861- if kind != "module" {
862- q .Set ("tab" , opt .TabID )
863- q .Set ("rt" , opt .RuntimeToken )
851+ if opt .ScriptURLRewriter == nil {
852+ return shareurl .ControlPrefix + "error/POLICY_BLOCKED" , "" , false
864853 }
865- return shareurl .ControlPrefix + "api/script?" + q .Encode (), abs .String (), true
854+ wrapped , target , err := opt .ScriptURLRewriter (raw , kind , opt .TargetURL .String (), shareurl .ControlPrefix , opt .TabID , opt .RuntimeToken )
855+ return wrapped , target , err == nil && wrapped != "" && target != ""
866856}
867857
868858func wrapFetchURL (raw string , opt Options ) (wrapped , target string , ok bool ) {
869- target , ok = resolveTargetURL (raw , opt )
870- if ! ok {
871- return shareurl .ControlPrefix + "error/POLICY_BLOCKED" , "" , false
872- }
873- networkTarget := target
874- fragment := ""
875- if u , err := url .Parse (target ); err == nil && u .Fragment != "" {
876- fragment = "#" + u .EscapedFragment ()
877- u .Fragment = ""
878- u .RawFragment = ""
879- networkTarget = u .String ()
859+ if opt .FetchURLRewriter == nil {
860+ return shareurl .ControlPrefix + "error/POLICY_BLOCKED" , "" , true
880861 }
881- q := url.Values {}
882- q .Set ("url" , networkTarget )
883- return shareurl .ControlPrefix + "api/fetch?" + q .Encode () + fragment , target , true
862+ wrapped , target , err := opt .FetchURLRewriter (raw , opt .TargetURL .String (), shareurl .ControlPrefix )
863+ return wrapped , target , err == nil && wrapped != "" && target != ""
884864}
885865
886866func isStylesheetLinkRel (rel string ) bool {
@@ -915,10 +895,10 @@ func executableScriptKind(tok xhtml.Token) string {
915895
916896func rewriteInlineScript (source , kind string , opt Options ) string {
917897 if strings .TrimSpace (source ) == "" {
918- return source
898+ return ""
919899 }
920900 if opt .ScriptRewriter != nil {
921- if code , err := opt .ScriptRewriter (source , kind , opt .TargetURL .String (), shareurl .ControlPrefix ); err == nil {
901+ if code , err := opt .ScriptRewriter (source , kind , opt .TargetURL .String (), shareurl .ControlPrefix , opt . TabID , opt . RuntimeToken ); err == nil {
922902 return code
923903 }
924904 }
@@ -930,106 +910,44 @@ func rewriteEventHandler(source string, opt Options) string {
930910 return source
931911 }
932912 if opt .ScriptRewriter != nil {
933- if code , err := opt .ScriptRewriter (source , "event-handler" , opt .TargetURL .String (), shareurl .ControlPrefix ); err == nil {
913+ if code , err := opt .ScriptRewriter (source , "event-handler" , opt .TargetURL .String (), shareurl .ControlPrefix , opt . TabID , opt . RuntimeToken ); err == nil {
934914 return code
935915 }
936916 }
937917 return `throw new DOMException('Blocked by ZeroProxy rewrite policy','NotSupportedError')`
938918}
939919
940920func rewriteInlineStyle (source string , opt Options ) string {
921+ if strings .TrimSpace (source ) == "" {
922+ return ""
923+ }
941924 if opt .CSSRewriter != nil {
942925 if code , err := opt .CSSRewriter (source , opt .TargetURL .String ()); err == nil {
943926 return code
944927 }
945928 }
946- return source
929+ return ""
947930}
948931
949932func rewriteInlineImportMap (source string , opt Options ) string {
950- if opt .ImportMapRewriter != nil {
951- code , err := opt .ImportMapRewriter (
952- source ,
953- opt .TargetURL .String (),
954- opt .TabID ,
955- opt .RuntimeToken ,
956- shareurl .ControlPrefix ,
957- )
958- if err != nil {
959- return `{}`
960- }
961- return code
962- }
963- return rewriteImportMap (source , opt )
964- }
965-
966- func blockScriptSource () string {
967- return `throw new DOMException('Blocked by ZeroProxy rewrite policy','NotSupportedError');`
968- }
969-
970- func rewriteImportMap (source string , opt Options ) string {
971- var doc map [string ]any
972- if err := json .Unmarshal ([]byte (source ), & doc ); err != nil {
933+ if opt .ImportMapRewriter == nil {
973934 return `{}`
974935 }
975- if imports , ok := doc [ "imports" ].( map [ string ] any ); ok {
976- rewriteImportMapAddresses ( imports , opt )
977- }
978- if scopes , ok := doc [ "scopes" ].( map [ string ] any ); ok {
979- doc [ "scopes" ] = rewriteImportMapScopes ( scopes , opt )
980- }
981- b , err := json . Marshal ( doc )
936+ code , err := opt . ImportMapRewriter (
937+ source ,
938+ opt . TargetURL . String (),
939+ opt . TabID ,
940+ opt . RuntimeToken ,
941+ shareurl . ControlPrefix ,
942+ )
982943 if err != nil {
983944 return `{}`
984945 }
985- return string ( b )
946+ return code
986947}
987948
988- // rewriteImportMapAddress maps a single import-map specifier address to its
989- // proxied module script URL, blocking non-http(s) targets.
990- func rewriteImportMapAddress (raw string , opt Options ) string {
991- u , err := url .Parse (strings .TrimSpace (raw ))
992- if err != nil {
993- return shareurl .ControlPrefix + "error/POLICY_BLOCKED"
994- }
995- abs := opt .TargetURL .ResolveReference (u )
996- if abs .Scheme != "http" && abs .Scheme != "https" {
997- return shareurl .ControlPrefix + "error/POLICY_BLOCKED"
998- }
999- q := url.Values {}
1000- q .Set ("kind" , "module" )
1001- q .Set ("u" , abs .String ())
1002- q .Set ("tab" , opt .TabID )
1003- q .Set ("rt" , opt .RuntimeToken )
1004- return shareurl .ControlPrefix + "api/script?" + q .Encode ()
1005- }
1006-
1007- // rewriteImportMapAddresses rewrites every string-valued address in a specifier
1008- // map in place.
1009- func rewriteImportMapAddresses (addresses map [string ]any , opt Options ) {
1010- for k , v := range addresses {
1011- if s , ok := v .(string ); ok {
1012- addresses [k ] = rewriteImportMapAddress (s , opt )
1013- }
1014- }
1015- }
1016-
1017- // rewriteImportMapScopes rewrites both the scope keys and their nested specifier
1018- // maps, returning a fresh map keyed by the rewritten scope addresses.
1019- func rewriteImportMapScopes (scopes map [string ]any , opt Options ) map [string ]any {
1020- next := make (map [string ]any , len (scopes ))
1021- for scope , rawEntries := range scopes {
1022- scopeKey := rewriteImportMapAddress (scope , opt )
1023- entries , _ := rawEntries .(map [string ]any )
1024- out := make (map [string ]any , len (entries ))
1025- for k , v := range entries {
1026- if s , ok := v .(string ); ok {
1027- out [k ] = rewriteImportMapAddress (s , opt )
1028- }
1029- }
1030- next [scopeKey ] = out
1031- }
1032- return next
949+ func blockScriptSource () string {
950+ return `throw new DOMException('Blocked by ZeroProxy rewrite policy','NotSupportedError');`
1033951}
1034952
1035953func injectSrcdoc (src string , opt Options ) string {
0 commit comments