Pooshit.Http
0.10.0-preview
See the version list below for details.
dotnet add package Pooshit.Http --version 0.10.0-preview
NuGet\Install-Package Pooshit.Http -Version 0.10.0-preview
<PackageReference Include="Pooshit.Http" Version="0.10.0-preview" />
<PackageVersion Include="Pooshit.Http" Version="0.10.0-preview" />
<PackageReference Include="Pooshit.Http" />
paket add Pooshit.Http --version 0.10.0-preview
#r "nuget: Pooshit.Http, 0.10.0-preview"
#:package Pooshit.Http@0.10.0-preview
#addin nuget:?package=Pooshit.Http&version=0.10.0-preview&prerelease
#tool nuget:?package=Pooshit.Http&version=0.10.0-preview&prerelease
Library simplifying http request handling
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Pooshit.Json (>= 0.3.40-preview)
-
net8.0
- Pooshit.Json (>= 0.3.40-preview)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.12.1-preview | 329 | 8/28/2026 |
| 0.10.0-preview | 147 | 8/27/2026 |
| 0.8.0-preview | 307 | 8/18/2026 |
| 0.7.18-preview | 464 | 6/25/2026 |
| 0.7.17-preview | 1,912 | 4/12/2026 |
| 0.7.16-preview | 75 | 4/11/2026 |
| 0.7.15-preview | 77 | 4/11/2026 |
| 0.7.9-preview | 862 | 2/5/2026 |
| 0.7.8-preview | 2,937 | 3/2/2025 |
| 0.7.7-preview | 1,511 | 10/15/2024 |
| 0.7.6-preview | 363 | 10/12/2024 |
Credential-bearing headers are now dropped when a followed redirect crosses origin. This is the change most likely to alter what a working caller observes, and the strip itself is never announced. With FollowRedirects enabled, the resolved target of the hop is compared against the request that produced the redirect: if scheme, host and port do not all match - RFC 6454 origin, so a subdomain is a different origin and a downgrade from https to http is one too - then every header whose name is in the sensitive set is left off the hop. A call that used to succeed can therefore now fail at the hop with a 401, and nothing reports the strip itself: a typed call surfaces it as the ordinary HttpServiceException any 401 would raise, and a call asking for the raw response returns the 401 for the caller to inspect. Neither distinguishes a credential that was deliberately withheld from one the target rejected, so the cause has to be inferred from the redirect having crossed origin. A target whose origin cannot be proven is treated as cross-origin and strips, which covers a response that carries no stamped request uri. A relative Location is mostly not such a case: it resolves against the url of the request that produced it, so a path-relative Location such as /target or ../target, and a bare query string, all stay in origin and keep their headers. The exception is a protocol-relative //host/path Location - relative, because it carries no scheme, but it supplies its own host, so it resolves off-origin and strips like any other cross-origin target. The comparison is made against the final url, after UrlProcessor and after uri combining, so what is judged is what the hop actually sends, and once a header has been stripped it is never restored. This is what browsers and curl -L have always done, and the reason is that Location is a value the remote server chooses: without the strip, a compromised or merely careless upstream can harvest a caller's bearer token by answering with a redirect to a host it names. Two escape hatches remain for a caller who genuinely needs a credential to cross a host boundary. Rewrite the target from UrlProcessor, which sees the resolved url before the hop is issued, so the hop goes to a host the caller named rather than one the server named. Or turn FollowRedirects off, take the raw reply with Get<HttpResponseMessage>, and issue the second call by hand carrying whatever headers it should carry. Unaffected: same-origin redirects; callers who never set FollowRedirects; and cross-origin redirects that carry no credential header to begin with.
A response carrying an unrecognised or absent Content-Type no longer throws InvalidCastException. The JSON family is now matched by structure instead of by exact string - application/json, text/json and any subtype carrying a +json suffix such as application/hal+json or application/vnd.acme.thing+json, all compared ignoring case - and any media type still unrecognised, including none at all, has its body inspected: a payload whose first meaningful character is { or [ is decoded with the configured decoder, and anything else raises HttpServiceException naming the request url, the received media type and the requested type, carrying the raw body on Body. Some paths escape that promise. A Content-Type declaring a character set the runtime does not know raises InvalidOperationException from the string read before the fallback is reached. An empty body does not reach the fallback at all: it returns the default value, unchanged from before and the same under a recognised media type. Nor does a request for string, byte[] or Stream, which hands the body back directly. This is what lets a server answering JSON under a media type it does not declare as JSON be read at all; Meta's Graph API answering text/javascript when no Accept header is sent is the case that prompted it. Caveat, and the one place this fix takes something away: asking for object, MemoryStream or IDisposable against an unrecognised media type used to hand back the undecoded body stream and no longer does - object yields the decoded value, MemoryStream yields an empty stream, and IDisposable raises HttpServiceException. A caller who wants the undecoded body should ask for Stream or byte[], both unaffected and always the right way to ask. Unchanged: every response whose media type already matched a branch - application/json, application/xml, text/xml, text/plain - and the raw Get<HttpResponseMessage> escape hatch.
HttpServiceException.Message no longer dumps credential-bearing header values. The header name survives and only the value is replaced, so the fact that an Authorization header was set stays visible while the token does not, and an exception logged by the usual reflex no longer writes a credential to the log. The policy is configurable per service through HttpService.HeaderDumpMode - Redacted, which is the new default; Omitted, which drops the header block entirely; or Full, which is the previous behaviour and now has to be asked for - and per call through HttpOptions.HeaderDumpMode, which falls back to the service when unset. The name set is HttpService.SensitiveHeaders, compared ignoring case and open for a consumer to extend or reduce - configure it before the service issues its first request, because it is read on every request and every dump and is not safe to mutate once the service is in use - and it ships with Authorization, Proxy-Authorization, Cookie, Set-Cookie, Api-Key, X-Api-Key, X-Auth-Token and X-Access-Token. WWW-Authenticate and Proxy-Authenticate are deliberately absent: a challenge header carries no client credential and is the most useful thing in a 401 dump. Note that this same name set also governs the cross-origin strip described above - one list, two behaviours - so a name added to it is both redacted out of exception messages and dropped from a cross-origin redirect hop, and a name removed from it loses both protections. Url, status and HttpServiceException.Body are unaffected, as is HttpServiceException.Response: a caller can still walk Response.RequestMessage.Headers, which is explicit access rather than accidental logging.
A followed redirect now inherits the headers of the request that produced it, instead of rebuilding them from the options bag. This is mostly a fix, and it earns a line because it changes what a Send<TResponse> caller observes: the hop used to carry the options bag's headers and none of the caller's own, so an Authorization, Accept or correlation id set on the pre-built request was silently dropped on the hop while the bag's headers - which the original request never carried - were added in their place. The hop now carries what the previous request carried, less the headers that describe a body the redirect does not have - Expect and Transfer-Encoding - and, when the hop leaves the origin, less every name in the sensitive set, which drops the caller's Authorization and Cookie along with it. For a url-based overload whose hop stays in origin the hop is wire-identical, with one observable difference: ITokenProvider.GetTokenAsync is now called once per call rather than once per hop, so a provider that mints single-use tokens will see the first one reused on the hop rather than a fresh one minted. A url-based hop that leaves the origin additionally goes out with no credential at all, where the old code sent a freshly minted one - the first item's change reaches this call shape too, and for most callers it matters more than the token count.