diff --git a/racket/collects/net/url.rkt b/racket/collects/net/url.rkt index 9564806d8b..94ca5650ea 100644 --- a/racket/collects/net/url.rkt +++ b/racket/collects/net/url.rkt @@ -4,6 +4,7 @@ racket/contract/base racket/list racket/match + racket/promise (prefix-in hc: "http-client.rkt") (only-in "url-connect.rkt" current-https-protocol) "uri-codec.rkt" @@ -23,27 +24,95 @@ ;; "impure" = they have text waiting ;; "pure" = the MIME headers have been read -(define current-proxy-servers - (make-parameter null - (lambda (v) - (unless (and (list? v) - (andmap (lambda (v) - (and (list? v) - (= 3 (length v)) - (equal? (car v) "http") - (string? (car v)) - (exact-integer? (caddr v)) - (<= 1 (caddr v) 65535))) - v)) - (raise-type-error - 'current-proxy-servers - "list of list of scheme, string, and exact integer in [1,65535]" +(define proxiable-url-schemes '("http")) + +(define (env->c-p-s-entries envars) + (if (null? envars) + null + (match (getenv (car envars)) + [#f (env->c-p-s-entries (cdr envars))] + ["" null] + [(app string->url + (url (and scheme "http") #f (? string? host) (? integer? port) + _ (list) (list) #f)) + (list (list scheme host port))] + [(app string->url + (url (and scheme "http") _ (? string? host) (? integer? port) + _ _ _ _)) + (log-net/url-error "~s contains somewhat invalid proxy URL format" (car envars)) + (list (list scheme host port))] + [inv (log-net/url-error "~s contained invalid proxy URL format: ~s" + (car envars) inv) + null]))) + +(define current-proxy-servers-promise + (make-parameter (delay (env->c-p-s-entries '("plt_http_proxy" "http_proxy"))))) + +(define (proxy-servers-guard v) + (unless (and (list? v) + (andmap (lambda (v) + (and (list? v) + (= 3 (length v)) + (equal? (car v) "http") + (string? (car v)) + (exact-integer? (caddr v)) + (<= 1 (caddr v) 65535))) v)) - (map (lambda (v) - (list (string->immutable-string (car v)) - (string->immutable-string (cadr v)) - (caddr v))) - v)))) + (raise-type-error + 'current-proxy-servers + "list of list of scheme, string, and exact integer in [1,65535]" + v)) + (map (lambda (v) + (list (string->immutable-string (car v)) + (string->immutable-string (cadr v)) + (caddr v))) + v)) + +(define current-proxy-servers + (make-derived-parameter current-proxy-servers-promise + (λ (v) (let ((guarded (proxy-servers-guard v))) + (delay guarded))) + force)) + +(define (env->n-p-s-entries envars) + (if (null? envars) + null + (match (getenv (car envars)) + [#f (env->n-p-s-entries (cdr envars))] + ["" null] + [hostnames (string-split hostnames ",")]))) + +(define current-no-proxy-servers-promise + (make-parameter (delay (no-proxy-servers-guard (env->n-p-s-entries '("plt_no_proxy" "no_proxy")))))) + +(define (no-proxy-servers-guard v) + (unless (and (list? v) + (andmap (lambda (v) + (or (string? v) + (regexp? v))) + v)) + (raise-type-error 'current-no-proxy-servers + "list of string or regexp" + v)) + (map (match-lambda + [(? regexp? re) re] + [(regexp "^(\\..*)$" (list _ m)) + (regexp (string-append ".*" (regexp-quote m)))] + [(? string? s) (regexp (string-append "^"(regexp-quote s)"$"))]) + v)) + +(define current-no-proxy-servers + (make-derived-parameter current-no-proxy-servers-promise + (λ (v) + (let ((guarded (no-proxy-servers-guard v))) + (delay guarded))) + force)) + +(define (proxy-server-for url-schm (dest-host-name #f)) + (let ((rv (assoc url-schm (current-proxy-servers)))) + (cond [(not dest-host-name) rv] + [(memf (lambda (np) (regexp-match np dest-host-name)) (current-no-proxy-servers)) #f] + [else rv]))) (define (url-error fmt . args) (raise (make-url-exception @@ -58,6 +127,7 @@ (cond [(not scheme) 80] [(string=? scheme "http") 80] [(string=? scheme "https") 443] + [(string=? scheme "git") 9418] [else (url-error "URL scheme ~s not supported" scheme)]))) ;; make-ports : url -> hc @@ -76,7 +146,7 @@ ;; -> hc (define (http://getpost-impure-port get? url post-data strings make-ports 1.1?) - (define proxy (assoc (url-scheme url) (current-proxy-servers))) + (define proxy (proxy-server-for (url-scheme url) (url-host url))) (define hc (make-ports url proxy)) (define access-string (ensure-non-empty @@ -326,7 +396,7 @@ [(get) "GET"] [(post) "POST"] [(head) "HEAD"] [(put) "PUT"] [(delete) "DELETE"] [(options) "OPTIONS"] [else (url-error "unsupported method: ~a" method)])] - [proxy (assoc (url-scheme url) (current-proxy-servers))] + [proxy (proxy-server-for (url-scheme url) (url-host url))] [hc (make-ports url proxy)] [access-string (ensure-non-empty @@ -387,7 +457,12 @@ (listof string?) any))) (current-proxy-servers - (parameter/c (or/c false/c (listof (list/c string? string? number?)))))) + (parameter/c (or/c false/c (listof (list/c string? string? number?))))) + (current-no-proxy-servers + (parameter/c (or/c false/c (listof (or/c string? regexp?))))) + (proxy-server-for (->* (string?) ((or/c false/c string?)) + (or/c false/c (list/c string? string? number?)))) + (proxiable-url-schemes (listof string?))) (define (http-sendrecv/url u #:method [method-bss #"GET"]