From e017d1f826053672ef8bf803c2409c17b488d6ea Mon Sep 17 00:00:00 2001 From: Laszlo Toth Date: Mon, 7 Dec 2015 17:05:01 +0100 Subject: [PATCH] [#102] Allow proplist headers --- README.md | 11 +++++++---- src/shotgun.erl | 21 +++++++++++---------- test/shotgun_SUITE.erl | 5 +++++ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index df5c790..c5a15db 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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`, @@ -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). ``` diff --git a/src/shotgun.erl b/src/shotgun.erl index 0fa9df3..9534030 100644 --- a/src/shotgun.erl +++ b/src/shotgun.erl @@ -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() @@ -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), @@ -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] diff --git a/test/shotgun_SUITE.erl b/test/shotgun_SUITE.erl index 328d005..4eef7d4 100644 --- a/test/shotgun_SUITE.erl +++ b/test/shotgun_SUITE.erl @@ -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()}.