Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions docs/instance-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Returns the HTTP request that `HttpCommand` would send when `Run` is executed an
<code> PrivateKeyFile</code><br/>
<code> PublicCertFile</code><br/>
<code> RequestOnly 0</code><br/>
<code> Secret 1</code><br/>
<code> SSLFlags 32</code><br/>
<code> SuppressHeaders 0</code><br/>
<code> Timeout 10</code><br/>
Expand Down Expand Up @@ -105,11 +106,21 @@ Returns the HTTP request that `HttpCommand` would send when `Run` is executed an
</table>

## Header-related Methods
There are two sets of headers associated with an HTTP request - the request headers and the response headers. The methods described here deal with request headers.
There are two sets of headers associated with an HTTP request - the request headers and the response headers. The methods described here deal with **request headers**.

`HttpCommand`'s request headers are stored in the `Headers` setting which is a 2-column matrix of name/value pairs. Header names are case-insensitive; header values are not. While you can manipulate the `Headers` array directly, `HttpCommand` has three methods to manage `Headers` that accommodate the case-insensitive nature of header names.

By default, `HttpCommand` will automatically generate several request headers. See [`SuppressHeaders`](operational-settings.md#suppressheaders) for the list of these headers. To suppress the generation of specific headers, you can set its value to `''`
By default, `HttpCommand` will automatically generate several request headers if you haven't specified values for them. See [`SuppressHeaders`](operational-settings.md#suppressheaders) for the list of these headers. To suppress the generation of specific headers, you can set its value to `''`.

You may specify that `HttpCommand` should substitute the value of an environment variable in a header name or value by surrounding the name of the environment variable with `%`. For example:
<pre><code> 1 HttpCommand.Get 'someurl.com' '' ('MyHeader' '%DYALOG%')
GET / HTTP/1.1
MyHeader: C:\Program Files\Dyalog\Dyalog APL-64 19.0 Unicode
Host: someurl.com
User-Agent: Dyalog-HttpCommand/5.5.0
Accept: */*
Accept-Encoding: gzip, deflate
</code></pre>

Note: The examples below were run using `]boxing on`.

Expand Down
29 changes: 29 additions & 0 deletions docs/operational-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,35 @@ If a folder is specified, the file name will be the same as the resource specifi
<td>This setting is useful for debugging a request that isn't behaving as you expect.<br/><br/>
Setting optional left argument of shared methods <code>Get</code>, <code>GetJSON</code>, <code>Do</code>, or <code>New</code> to <code>1</code> will have the same effect as setting <code>RequestOnly</code> as will the instance method <code>Show</code>.</td></tr></table>

### `Secret`
<table><tr>
<td>Description</td>
<td>If set to 1, <code>HttpCommand</code> will suppress the display of credentials in the Authorization header, instead replacing them with <code>&gt;&gt;&gt; Secret setting is 1 &lt;&lt;&lt;</code>. This applies when using the <a href="./instance-methods.md#show"><code>Show</code></a> or <a href="./instance-methods.md#config"><code>Config</code></a> methods or setting <a href="#requestonly"><code>RequestOnly</code></a> to 1. <code>Secret</code> will not affect the request that is actually sent to the host.</td></tr>
<tr><td>Default</td>
<td><code>1</code></td></tr>
<tr><td>Example(s)</td>
<td>
<pre><code> h←HttpCommand.New 'get' 'userid:password@someurl.com'
h.Show
GET / HTTP/1.1
Host: someurl.com
User-Agent: Dyalog-HttpCommand/5.5.0
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: >>> Secret setting is 1 <<<

h.Secret←0
h.Show
GET / HTTP/1.1
Host: someurl.com
User-Agent: Dyalog-HttpCommand/5.5.0
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Basic dXNlcmlkOnBhc3N3b3Jk
</code></pre></td></tr>
<tr><td>Details</td>
<td>This setting is useful when doing an <code>HttpCommand</code> demonstration as it will avoid inadvertently displaying credentials in the APL session.</td></tr></table>

### `SuppressHeaders`
<table><tr>
<td>Description</td>
Expand Down
3 changes: 3 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## Version 5.5
* Added configuration setting [`Secret`](./operational-settings.md#secret) which will suppress the display of credentials in the authorization header. This is primarily so that one can demo using authenticated requests without having their credentials displayed in the session.
* Added ability for HTTP header names and values to reference environment variables by enclosing the environment variable name in % (e.g. `%MyPassword%`). This provides additional security by reducing the need to store sensitive or variable information inline. This is particularly useful when setting [`Auth`](./request-settings.md#auth).
## Version 5.4
* Added function [`IsOK`](./result-operational.md#isok) to result namespace.
## Version 5.3
Expand Down
4 changes: 3 additions & 1 deletion docs/request-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ If the request has content in the request payload, Conga will automatically supp
### `Auth`
<table><tr>
<td>Description</td>
<td>This setting is the authentication/authorization string appropriate for the authentication scheme specified in <code>AuthType</code>. Used along with <a href="#authtype"><code>AuthType</code></a>, <code>Auth</code> is a shortcut for setting the authorization HTTP header for requests that require authentication. If <code>Auth</code> is non-empty, <code>HttpCommand</code> will create an <code>'authorization'</code> header and and set its value to <code>AuthType,' ',Auth</code>. If you happen set both <code>Auth</code> and an <code>authorization</code> header, <code>Auth</code> takes precedence.
<td>This setting is the authentication/authorization string appropriate for the authentication scheme specified in <code>AuthType</code>. Used along with <a href="#authtype"><code>AuthType</code></a>, <code>Auth</code> is a shortcut for setting the authorization HTTP header for requests that require authentication. If <code>Auth</code> is non-empty, <code>HttpCommand</code> will create an <code>'authorization'</code> header and and set its value to <code>AuthType,' ',Auth</code>. If you happen set both <code>Auth</code> and an <code>authorization</code> header, <code>Auth</code> takes precedence.<br/><br/>

You may specify an environment variable whose value is to be used for <code>Auth</code> by enclosing the environment variable name in <code>'%'</code>. This helps avoid the need to hardcode credentials in your code.
</td></tr>
<tr><td>Default</td><td><code>''</code></td></tr>
<tr><td>Example(s)</td><td><code>h.Auth←'my-secret-token'</code>
Expand Down
35 changes: 29 additions & 6 deletions source/HttpCommand.dyalog
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
∇ r←Version
⍝ Return the current version
:Access public shared
r←'HttpCommand' '5.4.6' '2024-02-28'
r←'HttpCommand' '5.5.0' '2024-03-07'

⍝ Request-related fields
Expand Down Expand Up @@ -46,6 +46,7 @@
:field public Timeout←10 ⍝ seconds to wait for a response before timing out, negative means reset timeout if any activity
:field public RequestOnly←¯1 ⍝ set to 1 if you only want to return the generated HTTP request, but not actually send it
:field public OutFile←'' ⍝ name of file to send payload to (format is same as ⎕NPUT right argument)
:field public Secret←1 ⍝ suppress displaying credentials in Authorization header
:field public MaxRedirections←10 ⍝ set to 0 if you don't want to follow any redirected references, ¯1 for unlimited
:field public KeepAlive←1 ⍝ default to not close client connection
:field public TranslateData←0 ⍝ set to 1 to translate XML or JSON response data
Expand Down Expand Up @@ -96,10 +97,14 @@
{}{0::'' ⋄ LDRC.Names'.'⊣LDRC.Close ⍵}⍣(~0∊⍴Client)⊢Client

∇ r←Config
∇ r←Config;i
⍝ Returns current configuration
:Access public
r←↑{6::⍵'not set' ⋄ ⍵(⍎⍵)}¨(⎕THIS⍎'⎕NL ¯2.2')~⊂'ValidFormUrlEncodedChars'
:If (≢r)≥i←r[;1]⍳⊂'Auth'
:AndIf Secret
r[i;2]←⊂'>>> Secret setting is 1 <<<'
:EndIf

∇ r←Run
Expand Down Expand Up @@ -564,15 +569,15 @@
:EndSelect

:If RequestOnly>SuppressHeaders ⍝ Conga supplies content-length, but for RequestOnly we need to insert it
hdrs←'Content-Length'(hdrs addHeader)⍴parms
hdrs←'Content-Length'(hdrs addHeader)⍴parms
:EndIf
:EndIf
:EndIf

hdrs⌿⍨←~0∊¨≢¨hdrs[;2] ⍝ remove any headers with empty values

:If RequestOnly
r←cmd,' ',(path,(0∊⍴urlparms)↓'?',urlparms),' HTTP/1.1',(∊{NL,⍺,': ',∊⍕⍵}/hdrs),NL,NL,parms
r←cmd,' ',(path,(0∊⍴urlparms)↓'?',urlparms),' HTTP/1.1',(∊{NL,⍺,': ',∊⍕⍵}/privatize environment hdrs),NL,NL,parms
→∆EXIT
:EndIf

Expand Down Expand Up @@ -699,7 +704,7 @@

(ConxProps←⎕NS'').(Host Port Secure certs)←r.(Host Port Secure),⊂certs ⍝ preserve connection settings for subsequent calls

:If 0=⊃rc←LDRC.Send Client(cmd(path,(0∊⍴urlparms)↓'?',urlparms)'HTTP/1.1'hdrs parms)
:If 0=⊃rc←LDRC.Send Client(cmd(path,(0∊⍴urlparms)↓'?',urlparms)'HTTP/1.1'(environment hdrs)parms)

∆LISTEN:
forceClose←~KeepAlive
Expand Down Expand Up @@ -1035,9 +1040,15 @@
11::⍵.Data←0(3⊃⎕RSI,##).⎕JSON ⍵.Data
⍵.Data←0(3⊃⎕RSI,##).⎕JSON⍠'Dialect' 'JSON5'⊢⍵.Data}

∇ r←GetEnv var
⍝ return enviroment variable setting for var
:Access public shared
r←2 ⎕NQ'.' 'GetEnvironment'var

∇ r←dyalogRoot
⍝ return path to interpreter
r←{⍵,('/\'∊⍨⊢/⍵)↓'/'}{0∊⍴t←2 ⎕NQ'.' 'GetEnvironment' 'DYALOG':⊃1 ⎕NPARTS⊃2 ⎕NQ'.' 'GetCommandLineArgs' ⋄ t}''
r←{⍵,('/\'∊⍨⊢/⍵)↓'/'}{0∊⍴t←GetEnv'DYALOG':⊃1 ⎕NPARTS⊃2 ⎕NQ'.' 'GetCommandLineArgs' ⋄ t}''

∇ ns←{ConxProps}ConnectionProperties url;p;defaultPort;ind;msg;protocol;secure;auth;host;port;path;urlparms
Expand Down Expand Up @@ -1290,6 +1301,18 @@
r←Headers

∇ hdrs←environment hdrs
⍝ substitute any header names or values that begin with '$env:' with the named environment variable
hdrs←(⍴hdrs)⍴'%[[:alpha:]].*?%'⎕R{GetEnv 1↓¯1↓⍵.Match}⊢,hdrs

∇ hdrs←privatize hdrs
⍝ suppress displaying Authorization header value if Private=1
:If Secret
hdrs[⍸hdrs[;1](∊ci)'Authorization' 'Proxy-Authorization';2]←⊂'>>> Secret setting is 1 <<<'
:EndIf

∇ r←{a}eis w;f
⍝ enclose if simple
f←{⍺←1 ⋄ ,(⊂⍣(⍺=|≡⍵))⍵}
Expand Down