Skip to content

Commit

Permalink
#65 do Auth with headers, instead of query params
Browse files Browse the repository at this point in the history
  • Loading branch information
sofakingworld committed Mar 15, 2023
1 parent 3fcff97 commit 791d5b4
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ through config.
config :pillar, Pillar.HttpClient, http_adapter: Pillar.HttpClient.TeslaMintAdapter
```

Adapter should define one function `post/3` and return 2 possible results (`%Pillar.HttpClient.Response{}`, `%Pillar.HttpClient.TransportError{}`)
Adapter should define one function `post/4` and return 2 possible results (`%Pillar.HttpClient.Response{}`, `%Pillar.HttpClient.TransportError{}`)

# Contribution

Expand Down
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ adapter =
config :pillar, Pillar.HttpClient, http_adapter: adapter

config :pillar,
connection_url: System.get_env("CLICKHOUSE_URL") || "http://localhost:8123"
connection_url: System.get_env("CLICKHOUSE_URL", "http://default@localhost:8123")
3 changes: 2 additions & 1 deletion lib/pillar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ defmodule Pillar do

defp execute_sql(connection, final_sql, options) do
timeout = Map.get(options, :timeout, @default_timeout_ms)
headers = Connection.headers_from_connection(connection)

connection
|> Connection.url_from_connection(options)
|> HttpClient.post(final_sql, timeout: timeout)
|> HttpClient.post(final_sql, headers, timeout: timeout)
|> ResponseParser.parse()
end

Expand Down
10 changes: 8 additions & 2 deletions lib/pillar/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@ defmodule Pillar.Connection do
}
end

def headers_from_connection(%__MODULE__{} = connect_config) do
[
{"X-ClickHouse-User", connect_config.user},
{"X-ClickHouse-Key", connect_config.password}
]
|> Enum.reject(fn {_k, v} -> is_nil(v) end)
end

def url_from_connection(%__MODULE__{} = connect_config, options \\ %{}) do
params =
reject_nils(%{
password: connect_config.password,
user: connect_config.user,
database: connect_config.database,
max_query_size: connect_config.max_query_size,
allow_suspicious_low_cardinality_types:
Expand Down
4 changes: 2 additions & 2 deletions lib/pillar/http_client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ defmodule Pillar.HttpClient do
Pillar.HttpClient.Response.t()
| Pillar.HttpClient.TransportError.t()
| RuntimeError.t()
def post(url, post_body \\ "", options \\ [timeout: 10_000]) do
def post(url, post_body \\ "", headers \\ [], options \\ [timeout: 10_000]) do
http_adapter = adapter()

if Code.ensure_loaded(http_adapter) && function_exported?(http_adapter, :post, 3) do
http_adapter.post(url, post_body, options)
http_adapter.post(url, post_body, headers, options)
else
%RuntimeError{message: "#{inspect(http_adapter)} is not loaded or unknown"}
end
Expand Down
10 changes: 8 additions & 2 deletions lib/pillar/http_client/httpc_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ defmodule Pillar.HttpClient.HttpcAdapter do
alias Pillar.HttpClient.Response
alias Pillar.HttpClient.TransportError

def post(url, post_body \\ "", options \\ [timeout: 10_000]) do
def post(url, post_body \\ "", headers \\ [], options \\ [timeout: 10_000]) do
headers =
headers
|> List.wrap()
|> Enum.map(fn {k, v} -> {String.to_charlist(k), String.to_charlist(v)} end)

result =
:httpc.request(
:post,
{String.to_charlist(url), [{'te', 'application/json'}], 'application/json', post_body},
{String.to_charlist(url), headers ++ [{'te', 'application/json'}], 'application/json',
post_body},
options,
[]
)
Expand Down
3 changes: 2 additions & 1 deletion lib/pillar/http_client/tesla_mint_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ defmodule Pillar.HttpClient.TeslaMintAdapter do
alias Pillar.HttpClient.Response
alias Pillar.HttpClient.TransportError

def post(url, post_body \\ "", options \\ [timeout: 10_000]) do
def post(url, post_body \\ "", headers \\ [], options \\ [timeout: 10_000]) do
timeout = Keyword.get(options, :timeout, 10_000)

middleware = [
Tesla.Middleware.FollowRedirects,
{Tesla.Middleware.Headers, headers},
{Tesla.Middleware.Timeout, timeout: timeout}
]

Expand Down
47 changes: 43 additions & 4 deletions test/pillar/connection_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defmodule Pillar.ConnectionTest do
}

assert Connection.url_from_connection(connection) ==
"https://localhost:8123/?database=default&password=password&user=user"
"https://localhost:8123/?database=default"
end

test "build valid url (no credentials and database)" do
Expand All @@ -75,17 +75,56 @@ defmodule Pillar.ConnectionTest do
}

assert Connection.url_from_connection(connection) ==
"https://localhost:8123/?database=default&password=password&user=user"
"https://localhost:8123/?database=default"

options = %{db_side_batch_insertions: true}

assert Connection.url_from_connection(connection, options) ==
"https://localhost:8123/?database=default&password=password&user=user&async_insert=1"
"https://localhost:8123/?database=default&async_insert=1"

options = %{db_side_batch_insertions: false}

assert Connection.url_from_connection(connection, options) ==
"https://localhost:8123/?database=default&password=password&user=user"
"https://localhost:8123/?database=default"
end
end

describe "#headers_from_connection" do
test "user and password passed" do
connection = %Connection{
database: "default",
host: "localhost",
scheme: "https",
user: "user",
password: "password",
port: 8123
}

assert Connection.headers_from_connection(connection) == [
{"X-ClickHouse-User", "user"},
{"X-ClickHouse-Key", "password"}
]
end

test "only user passed" do
connection = %Connection{
host: "localhost",
scheme: "https",
user: "user",
port: 8123
}

assert Connection.headers_from_connection(connection) == [{"X-ClickHouse-User", "user"}]
end

test "no credentials passed" do
connection = %Connection{
host: "localhost",
scheme: "https",
port: 8123
}

assert Connection.headers_from_connection(connection) == []
end
end
end

0 comments on commit 791d5b4

Please sign in to comment.