Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions http.carp
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,15 @@ attribute, whatever order the two appear in.")

(private target)
(hidden target)
; RFC 9110 §4.2.4: a request target never carries userinfo.
; RFC 9112 §3.2.1: an origin-form target with an empty path is sent as `/`.
(defn target [u]
(let [s (URI.str u)]
(if (and (Maybe.nothing? (URI.path u))
(Maybe.nothing? (URI.scheme u))
(Maybe.nothing? (URI.host u))
(Maybe.nothing? (URI.user u))
(Maybe.nothing? (URI.port u)))
(let [v (URI.set-password (URI.set-user @u (Maybe.Nothing)) (Maybe.Nothing))
s (URI.str &v)]
(if (and (Maybe.nothing? (URI.path &v))
(Maybe.nothing? (URI.scheme &v))
(Maybe.nothing? (URI.host &v))
(Maybe.nothing? (URI.port &v)))
(String.append "/" &s)
s)))

Expand Down
37 changes: 37 additions & 0 deletions test/http.carp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,12 @@
(fmt "%s=%s" (Cookie.name c) (Cookie.value c)))))
(Result.Error e) e))

; ---- request-target test helpers ----
(defn request-line [s]
(match (URI.parse s)
(Result.Success u) (Request.str &(Request.get u [] {} @""))
(Result.Error e) e))

(deftest test
(assert-true test
(match (Request.parse &simple-get) (Result.Success _) true _ false)
Expand Down Expand Up @@ -436,6 +442,37 @@
@""))
"absolute-form request-target is left alone")

(assert-equal test
"GET http://h.example/a/c HTTP/1.1\r\n\r\n"
&(request-line "http://USER:PW@h.example/a/c")
"request-target drops user and password")

(assert-equal test
"GET http://h.example/a/c HTTP/1.1\r\n\r\n"
&(request-line "http://USER@h.example/a/c")
"request-target drops a user without a password")

(assert-equal test
"GET http://h.example/a/c HTTP/1.1\r\n\r\n"
&(request-line "http://h.example/a/c")
"request-target without userinfo is unchanged")

(assert-equal test
"GET / HTTP/1.1\r\n\r\n"
&(Request.str
&(Request.get (URI.set-user (URI.zero) (Maybe.Just @"solo")) [] {} @""))
"request-target of a userinfo-only URI is /")

(assert-true test
(match (URI.parse "http://USER:PW@h.example/a/c")
(Result.Success u)
(let [r (Request.get u [] {} @"")]
(and
(= &(Maybe.Just @"USER") (URI.user (Request.uri &r)))
(= &(Maybe.Just @"PW") (URI.password (Request.uri &r)))))
_ false)
"the credentials stay on the request’s URI")

(assert-true test
(match (Cookie.parse "name=value")
(Result.Success c)
Expand Down