Access to Http headers

171 views
Skip to first unread message

Pierre Penninckx

unread,
Jan 8, 2014, 7:23:05 PM1/8/14
to elm-d...@googlegroups.com
I would like to access the Http headers of a request, be it a Success or a Failure.
While browsing the threads, it was evoked that the Http api will change so I suppose I can propose something.

A quick "fix" would be to change the Success and Failure constructors to:
    Success a [(String, String)]
    Failure Int String [(String, String)]
With the list of tuples the equivalent of the Request’s one.

The headers can be found by using the getAllResponseHeaders() function on the XMLHttpRequest (see: http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getallresponseheaders).

Second, there should indeed need to be a brainstorming around the api.
We could get rid of the Success constructor and replace the Failure by a Response one:
    Waiting
    Response Int String [(String, String)]
The Success constructor is very artificial since the test on the http status code is hardcoded. Furthermore, the status code is forgotten and no special treatment for the 201 code is possible.

Maybe not necessary, but there could be a finer-grained constructor for headers thanks to the XMLHttpRequest states (see http://www.w3.org/TR/XMLHttpRequest/#states):
    Waiting    — for UNSENT, OPENED, LOADING
    Headers    — for HEADERS_RECEIVED
    Response Int String    — for DONE

Also, there should be a way to set several parameters of the XMLHttpRequest, e.g. timeout.
Since there could be a lot of parameters, maybe switch to using a record would be a good idea?

Sorry for the random order of my ideas (it’s late here ^^), I’ll try to come with something more organized in the following days.
For now, I would simply like to know if the quick fix would be an acceptable way to go.

Thanks!
----
Pierre Penninckx   [ibiza...@gmail.com]

Jeff Smits

unread,
Jan 10, 2014, 7:23:18 AM1/10/14
to elm-discuss
Pierre, I always interpreted the plans to change the HTTP library as changes that makes it easier work with within a Signal context. But if you need a general HTTP improvement where more low-level stuff is exposed, I guess that's possible too. I suspect that once ports are working, it will become much easier to write an HTTP library yourself. I think it will take some time before that's ready, but I doubt any changes like this will be made to HTTP library before ports and better JS(ON) integration are done.
I can't really say much about your proposal itself, I don't know enough about HTTP and XMLHttpRequest. But if you want to formalise this proposal, that will certainly help to speed things up: https://github.com/evancz/Elm/blob/master/How%20to%20Request%20Features.md

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Pierre Penninckx

unread,
Jan 10, 2014, 8:32:23 AM1/10/14
to elm-discuss
I must say I don't know a lot either on HTTP and XMLHttpRequest.

The actual request is that I need immediate (as in not tomorrow) access to the headers of the message. That's not a big deal: I forked Elm and nearly finished implementing it already. I'll do a PR when it's ready if someone needs it (it's basically 15 LOC).
So I don't really need a full-fledged Http api.

And about the signal-friendly changes, is there a discussion taking place somewhere?


2014/1/10 Jeff Smits <jeff....@gmail.com>

Conrad Parker

unread,
Jan 10, 2014, 4:18:19 PM1/10/14
to elm-d...@googlegroups.com
On 9 January 2014 11:23, Pierre Penninckx <ibiza...@gmail.com> wrote:

Maybe not necessary, but there could be a finer-grained constructor for headers thanks to the XMLHttpRequest states (see http://www.w3.org/TR/XMLHttpRequest/#states):
    Waiting    — for UNSENT, OPENED, LOADING
    Headers    — for HEADERS_RECEIVED
    Response Int String    — for DONE


this API (plus the timeout) sounds good. A simpler API could be built on top of it for the usual "get or fail" async load.

Conrad. 

John Mayer

unread,
Jan 10, 2014, 6:50:37 PM1/10/14
to elm-d...@googlegroups.com

Ideally we would write something called ajax that took a big config record. The existing methods would be rewritten to use some default configs without changing their api.

--

Pierre Penninckx

unread,
Jan 10, 2014, 7:03:43 PM1/10/14
to elm-d...@googlegroups.com
Jeff, I think I stumbled on something totally related to what you said: "make it easier to work within a Signal context".

Here is what I want to solve:
I want to speak with a server who's protocol is the following. By the way, I cannot change this behaviour.
On first request there is a handshake:
1/ client sends request,
2/ server answers back with a 409 (conflit) error plus an additional header containing a key,
3/ the client sends back the same request plus the header containing the key.
4/ server answers with 200 (well, normally)
On subsequent requests, do 3 and 4. That is easy to implement, here is where it gets tough (for me).
After a certain amount of time, the server can answer with a "2" even though the client sent a "3", the client must then resend a "3" with the new key. In other words, the key can change throughout the transaction.
For the curious, this was implemented to prevent CSRF attacks.

I would like this handshaking to be completely transparent for the user. At least as much as possible.

Here is what I came up to (pseudocode!). Like I said in a previous mail, I added the headers to the Http.Response.

The problem is that I cannot make nested Http.send calls. Or can I?
Could a behaviour like this break purity?

----
Pierre Penninckx   [ibiza...@gmail.com]



Jeff Smits

unread,
Jan 12, 2014, 5:41:57 AM1/12/14
to elm-discuss
Nested send calls are not an option. 

Your protocol looks implementable at first glance but I don't think it currently is... It has to do with signal vs state limitations. So it looks like it has everything to do with making the API easier to use in a Signal context. 
This is probably resolvable on an API level. I'm working on a language-level solution myself, but that's still vaguely defined theory and will not be available within a few months. 

You can try to devise an API that will resolve this in a nice way, but that's pretty hard to do (it's been postponed by everyone else for a reason ;) ). You can also implement the protocol in JavaScript and use the FFI. Do note that there are fragility issues with the current implementation of the FFI and Evan is working hard on a new and better system for the next release. You might consider building the dev version of the Elm compiler from source (it's not hard) so you can use this new stuff already. 

Pierre Penninckx

unread,
Jan 21, 2014, 6:29:55 AM1/21/14
to elm-discuss
I tried to make this mail as short and as clear as possible.

Background research
Having tried a lot of implementations, always stumbling on the non-existence of a `join : Signal (Signal a) -> Signal a` function, I searched why nested signals, i.e. "Signal Signal a" was not an option. I found this thread. It was very informative and made me see the light. ;)

Then, having seen that automatons are defined as Signal a -> Signal b, like the Http.send function, I searched for automatons and stumbled upon this thread and saw that Evan already thought about Http as an automaton!


The following two paragraphs explain what is IMO making the current Http library wobbly.

Even though there are "a -> Signal b" functions which seems to create a signal, conceptually you use something which exists before the program is launched.  What it does is, at the start of the program, create an external element (not Element) which will then fire some signals for various reasons (user input, timer, etc.). The reason they are fired is always external. The key here is that you can consider the lifetime of the element sending the signal to be longer then the one of your program. When you create a button, it exists from the start until the end of the program and sends a continuous stream. Like said in the thread, this allows and forces you to write most of your code in a pure language and lift those functions on signals at the last moment.

Http.send does not play well in this frame. Here the lifetime of the request is short compared to the lifetime of the whole program. Each time the entry signal changes, you create a new request. So Elm "lies" about this and abstracts this creation of new requests and shows only one timeline. Each time a new request is sent, elm switches to the new object transparently and you receive the events of the new object. The previous one is then destroyed. This is a nice abstraction but it is a fundamentally different signal paradigm. Should it be treated differently?
Is this related to what you are trying to solve, Jeff?

Solutions
Based on this, I see two ways to implement the protocol I mentioned earlier.
1/ Make Http requests synchronous:
    send : Request String -> Response String
Nesting requests become evident.

I don't know what this solution would imply. Is this good?

2/ Use ports.
Instead of sending Http requests from Elm, I would send Http request from Javascript in this way (the end user would only see the first and the last step):
a. Ask something to the server implementing the protocol.
b. Send request through port (to JS).
c. If present, add the id in the headers of the request.
d. Send back the request through port and use Elm's Http library.
e. Intercept the response (in JS!) and see if it is a 409 error. If it is, extract the new id and go back to c.
f. Send back the response to Elm for the user to intercept.

So a request will be exchanged multiple times between Elm and JS through ports (Elm -> JS -> Elm -> JS -> Elm). Is it clear?
I could do (Elm -> JS -> Elm) but it would not be funny.

Http API Revamp
This is only needed if I use Elm to send the actual Http request. I need to change the library interface like this:
  type Headers = Dict.Dict String String
  type Request = {
    verb : String,
    url : String,
    body : a,
    headers : Headers
  }
  data Response a = Success a Headers
                  | Waiting
                  | Failure Int String Headers
Two remarks: First, this is a minimal change of the API to include headers, only a gentle step towards a full-fledged Http API. Second, is there a reason to not impose a = String?

I hope to do a PR this evening (in Belgium thus UTC +1) with the Http API proposal (Elm and JS code). The library implementing the protocol with ports will come later.

2014/1/12 Jeff Smits <jeff....@gmail.com>

Jeff Smits

unread,
Jan 22, 2014, 6:36:26 AM1/22/14
to elm-discuss
That's not what I'm trying to solve. I'm trying to solve being able to define your solution 2 in Elm.
I guess it makes sense that you find the signal abstraction a misfit for consecutive http messages. The problem with your first solution is that sending a request is asynchronous and can have a big latency. Do you really want to block your whole application until you receive a response? Elm was designed to be the easy solution to a responsive GUI, so blocking IO doesn't sound like a good solution...

Pierre Penninckx

unread,
Jan 22, 2014, 9:32:48 AM1/22/14
to elm-discuss
We agree that the first solution is not option.

How do you plan enabling solution 2 in Elm? Is it by making Signal a monad or something else?
I would love to know what is your idea.


2014/1/22 Jeff Smits <jeff....@gmail.com>

Jeff Smits

unread,
Jan 22, 2014, 10:07:10 AM1/22/14
to elm-discuss
The talk I gave at the workshop in Budapest last year is probably the best explanation, but the recording of that talk is not online yet :(
If I'd had time to explain it thoroughly in text I would have already... For now the only explanation is scattered through some mailing-list discussions that expect prior knowledge. I would advise you to wait for the video of the talk rather than wading through all the emails that were pretty much work in progress. OTOH, when those recordings will be online is something nobody knows =\

Pierre Penninckx

unread,
Jan 22, 2014, 10:32:36 AM1/22/14
to elm-discuss
No worries: anyway I'm too eager to know to wait for the videos to come out ;)


2014/1/22 Jeff Smits <jeff....@gmail.com>
Reply all
Reply to author
Forward
0 new messages