Search code examples
httpcookiesrebolrebol3

How do I pass a URL a cookie using Rebol 3 and get the response cookies?


This stackoverflow question - How do I pass a URL a cookie using Rebol 3? - almost answers my question, but I am not sure how to capture the cookies from the response.

What I would like to do is call to a URL passing in cookies (and headers) and to be able to view the response and the cookies (and headers).

I think what I need to do is to open the port then I can query the response. Something like this:

site: open http://rebol.com
write site [ GET [ Cookie: {test=1}] ]
query site
close site

Is this the best approach?


Solution

  • I do this using an http protocol that has been modified to

    1. use an optional headers word in the write dialect that returns the port object so you can inspect the body and header
    2. return an error object with the port object when an error eg. a manual redirect is required.

    The file is available at:

    https://raw.githubusercontent.com/gchiu/Rebol3/master/protocols/prot-http.r3

    >> do https://raw.githubusercontent.com/gchiu/Rebol3/master/protocols/prot-http.r3
    >> a: write http://stackoverflow.com [ headers "" ]
    >> probe a/spec/debug/headers/set-cookie
    [{__cfduid=d349046701c0e9fd9f8858fa4b406ff141438752651; expires=Thu, 04-Aug-16 0
    5:30:51 GMT; path=/; domain=.stackoverflow.com; HttpOnly} {prov=f1a9c7a9-cd49-44
    82-94e0-4594c7991c19; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:
    00 GMT; path=/; HttpOnly}]
    

    Here is a .patch file of what's different from the http.r that's currently used by Atronix and Ren/C:

    diff --git a/src/mezz/prot-http.r b/src/mezz/prot-http.r
    index 426f115..dfa344a 100644
    --- a/src/mezz/prot-http.r
    +++ b/src/mezz/prot-http.r
    @@ -11,16 +11,27 @@ REBOL [
        }
        Name: 'http
        Type: 'module
    -   Version: 0.1.4
    -   File: %prot-http.r
    +   Version: 0.1.45
    +   File: %prot-http.r3
        Purpose: {
            This program defines the HTTP protocol scheme for REBOL 3.
        }
    -   Author: ["Gabriele Santilli" "Richard Smolak"]
    -   Date: 26-Nov-2012
    +   Author: ["Gabriele Santilli" "Richard Smolak" "Graham Chiu"]
    +   notes: {modified to return an error object with the info object when manual redirect required - Graham}
    +   Date: 27-April-2014
     ]
    
    -sync-op: func [port body /local state] [
    +digit: charset [ #"0" - #"9" ]
    +alpha: charset [ #"a" - #"z" #"A" - #"Z" ]
    +idate-to-date: func [ date [string!] /local day month year time zone]
    +[
    +   either parse date [ 5 skip copy day 2 digit space copy month 3 alpha space copy year 4 digit space copy time to space space copy zone to end ][
    +       if zone = "GMT" [ zone: copy "+0" ]
    +       to date! ajoin [ day "-" month "-" year "/" time zone ]
    +   ][ none ]
    +]
    +
    +sync-op: func [port body /local state ] [
        unless port/state [open port port/state/close?: yes]
        state: port/state
        state/awake: :read-sync-awake
    @@ -35,7 +46,11 @@ sync-op: func [port body /local state] [
        ]
        body: copy port
        if state/close? [close port]
    -   body
    +   either port/spec/debug [
    +       state/connection/locals
    +   ][
    +       body
    +   ]
     ]
     read-sync-awake: func [event [event!] /local error] [
        switch/default event/type [
    @@ -111,12 +126,34 @@ http-awake: func [event /local port http-port state awake res] [
     make-http-error: func [
        "Make an error for the HTTP protocol"
        message [string! block!]
    +   /inf obj
    +   /otherhost new-url [url!]
     ] [
        if block? message [message: ajoin message]
    -   make error! [
    -       type: 'Access
    -       id: 'Protocol
    -       arg1: message
    +   case [
    +       inf [
    +           make error! [
    +               type: 'Access
    +               id: 'Protocol
    +               arg1: message
    +               arg2: obj
    +           ]
    +       ]
    +       otherhost [
    +           make error! [
    +               type: 'Access
    +               id: 'Protocol
    +               arg1: message
    +               arg3: new-url
    +           ]
    +       ]
    +       true [
    +           make error! [
    +               type: 'Access
    +               id: 'Protocol
    +               arg1: message
    +           ]
    +       ]
        ]
     ]
     http-error: func [
    @@ -174,9 +211,11 @@ do-request: func [
        make-http-request spec/method to file! any [spec/path %/]
        spec/headers spec/content
     ]
    -parse-write-dialect: func [port block /local spec] [
    +parse-write-dialect: func [port block /local spec debug] [
        spec: port/spec
    -   parse block [[set block word! (spec/method: block) | (spec/method: 'post)]
    +   parse block [
    +       opt [ 'headers ( spec/debug: true ) ] 
    +       [set block word! (spec/method: block) | (spec/method: 'post)]
            opt [set block [file! | url!] (spec/path: block)] [set block block! (spec/headers: block) | (spec/headers: [])] [set block [any-string! | binary!] (spec/content: block) | (spec/content: none)]
        ]
     ]
    @@ -197,7 +236,7 @@ check-response: func [port /local conn res headers d1 d2 line info state awake s
            info/headers: headers: construct/with d1 http-response-headers
            info/name: to file! any [spec/path %/]
            if headers/content-length [info/size: headers/content-length: to integer! headers/content-length]
    -       if headers/last-modified [info/date: attempt [to date! headers/last-modified]]
    +       if headers/last-modified [info/date: attempt [idate-to-date headers/last-modified]]
            remove/part conn/data d2
            state/state: 'reading-data
        ]
    @@ -237,6 +276,9 @@ check-response: func [port /local conn res headers d1 d2 line info state awake s
                | (info/response-parsed: 'version-not-supported)
            ]
        ]
    +   if all [logic? spec/debug true? spec/debug]  [
    +       spec/debug: info
    +   ]
        switch/all info/response-parsed [
            ok [
                either spec/method = 'head [
    @@ -276,7 +318,7 @@ check-response: func [port /local conn res headers d1 d2 line info state awake s
                    ] [
                        res: do-redirect port headers/location
                    ] [
    -                   state/error: make-http-error "Redirect requires manual intervention"
    +                   state/error: make-http-error/inf "Redirect requires manual intervention" info
                        res: awake make event! [type: 'error port: port]
                    ]
                ]
    @@ -364,7 +406,7 @@ do-redirect: func [port [port!] new-uri [url! string! file!] /local spec state]
            do-request port
            false
        ] [
    -       state/error: make-http-error "Redirect to other host - requires custom handling"
    +       state/error: make-http-error/otherhost "Redirect to other host - requires custom handling" to-url rejoin [new-uri/scheme "://" new-uri/host new-uri/path]
            state/awake make event! [type: 'error port: port]
        ]
     ]
    @@ -449,6 +491,7 @@ sys/make-scheme [
            headers: []
            content: none
            timeout: 15
    +       debug: none
        ]
        info: make system/standard/file-info [
            response-line: