Skip to content

Commit

Permalink
[inaka#102] Allow proplist headers
Browse files Browse the repository at this point in the history
  • Loading branch information
tothlac committed Dec 14, 2015
1 parent 13b6b44 commit e017d1f
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 14 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ For the times you need more than just a [gun](http://github.com/extend/gun).
After using the [gun](http://github.com/extend/gun) library on a project where
we needed to consume Server-sent Events (SSE) we found that it provided great
flexibility, at the cost of having to handle each raw message and data,
including the construction of the reponse body data.
including the construction of the response body data.
Although this is great for a lot of scenarios, it can get cumbersome and
repetitive after implementing it a couple of times. This is why we ended up
creating **shotgun**, an HTTP client that uses **gun** behind the curtains but
Expand Down Expand Up @@ -66,8 +66,9 @@ Which results in:
Immediately after opening a connection we did a GET request, where we didn't
specify any headers or options. Every HTTP method has its own **shotgun**
function that takes a connection, a uri (which needs to include the slash),
a headers map and an options map. Some of the functions (`post/5`, `put/5`
and `patch/5`) also take a body argument.
a headers map or a proplist containing the headers, and an options map.
Some of the functions (`post/5`, `put/5` and `patch/5`) also take a body
argument.

Alternatively there's a generic `request/6` function in which the user can
specify the HTTP method as an argument in the form of an atom: `get`, `head`,
Expand All @@ -91,7 +92,9 @@ as easy as specifying a `basic_auth` entry in the headers map:

```erlang
{ok, Conn} = shotgun:open("site.com", 80),
{ok, Response} = shotgun:get(Conn, "/user", #{basic_auth => {"user", "password"}),
{ok, Response} = shotgun:get(Conn, "/user", #{basic_auth => {"user", "password"}}),
, or
{ok, Response} = shotgun:get(Conn, "/user", [{basic_auth, {"user", "password"}}]),
shotgun:close(Conn).
```

Expand Down
21 changes: 11 additions & 10 deletions src/shotgun.erl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
-type connection() :: pid().
-type http_verb() :: get | post | head | delete | patch | put | options.
-type uri() :: iodata().
-type headers() :: #{}.
-type headers() :: #{} | proplists:proplist().
-type body() :: iodata() | body_chunked.
-type options() ::
#{ async => boolean()
Expand Down Expand Up @@ -627,8 +627,8 @@ manage_chunk(IsFin, StreamRef, Data,
NewState.

%% @private
-spec process_options(map(), map(), http_verb()) -> map().
process_options(Options, HeadersMap, HttpVerb) ->
-spec process_options(map(), headers(), http_verb()) -> map().
process_options(Options, Headers, HttpVerb) ->
Headers = basic_auth_header(HeadersMap),
HandleEvent = maps:get(handle_event, Options, undefined),
Async = maps:get(async, Options, false),
Expand All @@ -647,14 +647,15 @@ process_options(Options, HeadersMap, HttpVerb) ->
}.

%% @private
-spec basic_auth_header(map()) -> list().
-spec basic_auth_header(headers()) -> proplists:proplist().
basic_auth_header(Headers) when is_map(Headers) ->
basic_auth_header(maps:to_list(Headers));
basic_auth_header(Headers) ->
case maps:get(basic_auth, Headers, undefined) of
undefined ->
maps:to_list(Headers);
{User, Password} ->
HeadersClean = maps:remove(basic_auth, Headers),
HeadersList = maps:to_list(HeadersClean),
case lists:keyfind(basic_auth, 1, Headers) of
false ->
Headers;
{_, {User, Password}} = Res ->
HeadersList = lists:delete(Res, Headers),
Base64 = encode_basic_auth(User, Password),
BasicAuth = {<<"Authorization">>, <<"Basic ", Base64/binary>>},
[BasicAuth | HeadersList]
Expand Down
5 changes: 5 additions & 0 deletions test/shotgun_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ basic_auth(Config) ->
{ok, Response2} = shotgun:get(Conn, "/basic-auth", Headers),
#{status_code := 200} = Response2,

%% try the same request using proplists
{ok, Response3} = shotgun:get(Conn, "/basic-auth",
[{basic_auth, {"user", "pass"}}]),
#{status_code := 200} = Response3,

{comment, ""}.

-spec get(shotgun_test_utils:config()) -> {comment, string()}.
Expand Down

0 comments on commit e017d1f

Please sign in to comment.